Название: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 19, 2009, 08:36 Есть такой код:
#include "iostream" class A { public: int b; void Pokaz(){printf("Pokaz\n");}; }; int main() { try { A *a=0; a->b=5; a->Pokaz(); } catch(...) { printf("try\n"); }; }; При выполнении выдает следующее: [root@localhost ~]# /usr/NULL/Null/Debug/Null Ошибка сегментирования [root@localhost ~]# Почему не срабатывает try? Название: Re: Почему не срабатывает блок try? Отправлено: Пантер от Август 19, 2009, 09:10 С какими параметрами собрана Qt?
Название: Re: Почему не срабатывает блок try? Отправлено: pastor от Август 19, 2009, 09:27 А причем здесь Qt?
Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 19, 2009, 09:30 Qt здесь не использовалась, но код с использование Qt в такой же ситуации тоже не работает правильно. В этом примере ошибка выделена в простом коде.
Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 19, 2009, 09:43 А кто сказал, что плюсовый try должен отрабатывать такие исключения? ;)
Название: Re: Почему не срабатывает блок try? Отправлено: Авварон от Август 19, 2009, 09:45 а я чего-то не понимаю, или исключение некому бросать? сегфолт - это системное событие а не результат системного вызова (как при new). Я бы сказал, что это не исключение...
Название: Re: Почему не срабатывает блок try? Отправлено: Winstrol от Август 19, 2009, 10:09 Почему не срабатывает try? Под windows разыменование нулевого указателя это так называемое SEH-исключение, а не с++-исключение. Для того, чтобы его ловить в блоке catch, нужно установить функцию транслирующую SEH в с++-исключения с помощью вызова системной _set_se_translator. Примнры кода можно найти поиском по _set_se_translator.Название: Re: Почему не срабатывает блок try? Отправлено: Пантер от Август 19, 2009, 11:29 А причем здесь Qt? :) Что-то вспомнилось про ключик -exeption. Ошибся малость.Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 20, 2009, 09:53 Посмотрел я в интернете, прошелся поиском по своему линуксу, и что то ничего нет. В интернете есть примеры только для виндов. Что же, под линуксом ничего сделать невозможно?
Название: Re: Почему не срабатывает блок try? Отправлено: denka от Август 20, 2009, 10:11 Возможно - перед обращением к указателю проверять валидный ли он
Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 20, 2009, 10:13 Посмотрел я в интернете, прошелся поиском по своему линуксу, и что то ничего нет. В интернете есть примеры только для виндов. Что же, под линуксом ничего сделать невозможно? Почитай про системные сигналы в linux. Для начала man signal.Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 20, 2009, 10:20 Возможно - перед обращением к указателю проверять валидный ли он Вот это то мне и надо, но как это сделать без возникновения исключения? Если возможно, приведи код. Буду очень благодарен. Название: Re: Почему не срабатывает блок try? Отправлено: ритт от Август 20, 2009, 10:44 Код: if (ptr) ptr->doSomething(); Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 20, 2009, 12:45 Код: if (ptr) ptr->doSomething(); if (ptr) printf("валидный указатель"); else printf("Не валидный указатель"); delete ptr; printf(Удалили); При ptr=NULL получаю: Не валидный указатель Удалили При ptr указывающий на самоудалившийся процесс, получаю: валидный указатель И все, сообщение "Удалили" я не получаю, программа вылетает на delete ptr. Как мне проверить, объект удален из памяти или нет? В программе с Qt ptr указывает на процесс. Название: Re: Почему не срабатывает блок try? Отправлено: Rcus от Август 20, 2009, 12:53 Классический случай dangling pointer.
Что значит указывает на процесс, всмысле на объект класса QProcess? Тогда QPointer же. Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 20, 2009, 13:45 Это продолжение темы
http://www.prog.org.ru/index.php?topic=10158.msg61489#msg61489 Только в родительском классе создается объект PotokThread и запускается на выполенение, его адрес при завершении программы проверяется на валидность. Вот там у меня грабли. Как мне проверить валидность указателя на объект? Название: Re: Почему не срабатывает блок try? Отправлено: pastor от Август 20, 2009, 13:48 А зачем проверять валидность указателя на объект PotokThread при завершении работы приложения? Расскажи лучше, что нужно получить в итоге? Для чего эти проверки?
Название: Re: Почему не срабатывает блок try? Отправлено: Igors от Август 20, 2009, 14:28 Код: if (ptr) ptr->doSomething(); if (ptr) printf("валидный указатель"); else printf("Не валидный указатель"); delete ptr; printf(Удалили); При ptr=NULL получаю: Не валидный указатель Удалили При ptr указывающий на самоудалившийся процесс, получаю: валидный указатель И все, сообщение "Удалили" я не получаю, программа вылетает на delete ptr. Как мне проверить, объект удален из памяти или нет? В программе с Qt ptr указывает на процесс. delete(ptr); ptr = 0; Чтобы полностью исключить его дальнейшее использование. Любые действия с уже удаленным указателем ведут к очень тяжелым последствиям (просто вылет = самое лучшее из них). Ваш текст будет работать как Вы описали если, например, если вы вызвали delete второй раз для того же указателя. Использование exception в данном случае ничего не даст а только запутает: ptr может быть "корректным адресом" но данные по этому адресу уже разрушены, хуже того - этот адрес может уже используется для совершенно других данных. Чтобы найти ошибку надо смотреть все что делается с указателем начиная с его создания (обычно new). Это может быть очень непросто но других методов нет. Название: Re: Почему не срабатывает блок try? Отправлено: kuzulis от Август 20, 2009, 14:59 Цитировать if (ptr) printf("валидный указатель"); 1. Нужно было при самоудалении процесса обнулять указатель на него. По ходу два раза delete вызывается (как говорили выше)else printf("Не валидный указатель"); delete ptr; printf(Удалили); При ptr=NULL получаю: Не валидный указатель Удалили При ptr указывающий на самоудалившийся процесс, получаю: валидный указатель И все, сообщение "Удалили" я не получаю, программа вылетает на delete ptr. Как мне проверить, объект удален из памяти или нет? В программе с Qt ptr указывает на процесс. т.е. объект удалили, а указатель забыли обнулить, при этом в переменной ptr остался адрес удаленного объекта (но объекта уже не существует)! И может быть этот адрес уже используется другим процессом и т.п. Поэтому и вылетает! :) (если я правильно понял ситуевину) 2. Не нужно при указателе = NULL удалять его :) т.е. типо так нужно: Код: if (ptr) printf("валидный указатель"); Название: Re: Почему не срабатывает блок try? Отправлено: kuzulis от Август 20, 2009, 15:08 т.е наверное у вас что то типо этого:
Код: class A при таком раскладе приложение вылетит Название: Re: Почему не срабатывает блок try? Отправлено: pastor от Август 20, 2009, 16:29 2. Не нужно при указателе = NULL удалять его :) Абсолютно ничего не произойдет при: Код
0-й указатель "удалять" можно. Название: Re: Почему не срабатывает блок try? Отправлено: hamlo от Август 20, 2009, 20:51 Код: class A{ Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 21, 2009, 09:17 Вот код:
void Potok::ZapuskThread() { Pt=new PotokThread((QObject*)this); connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection); Pt->start(); }; Potok::~Potok() { delete Pt; }; Если происходит прерывание программы пока PotokThread не завершился, происходит утечка памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его валидность. Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 21, 2009, 09:25 Если происходит прерывание программы пока PotokThread не завершился, происходит утечка Это если в PotokThread запущен цикл обработки событий:памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его валидность. Код
Если не запущен, нужно добавить код, который будет завершать нить и в деструкторе вызвать метод остановки потока и wait. Название: Re: Почему не срабатывает блок try? Отправлено: spectre71 от Август 21, 2009, 09:26 Вот код: После void Potok::ZapuskThread() { Pt=new PotokThread((QObject*)this); connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection); Pt->start(); }; Potok::~Potok() { delete Pt; }; Если происходит прерывание программы пока PotokThread не завершился, происходит утечка памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его валидность. connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); Pt->start(); НЕЛЯЗЯ ДЕЛАТЬ!!! delete Pt; Может получить повторное удаление Pt! Это баг! Если происходит прерывание программы система освобождает ресурсы связанные с ней и никакой утечки нет. Название: Re: Почему не срабатывает блок try? Отправлено: pastor от Август 21, 2009, 11:02 Если происходит прерывание программы пока PotokThread не завершился Я уже предлагал вариант завершения потока при завершении работы приложения. Не подходит такой вариант? Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 21, 2009, 12:16 Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль. Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы?
Название: Re: Почему не срабатывает блок try? Отправлено: Igors от Август 21, 2009, 12:20 Вот код: В С/C++ не существует способа проверить валидность указателя, надо полагаться на то что все операции с ним были корректны. В данном случае Вы перестарались и удаляете дважды :) Одно из удалений надо убратьvoid Potok::ZapuskThread() { Pt=new PotokThread((QObject*)this); connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); QObject::connect(Pt, SIGNAL(valueChanged(int)), ui.Zapolnenie, SLOT(setValue(int)), Qt::QueuedConnection); Pt->start(); }; Potok::~Potok() { delete Pt; }; Если происходит прерывание программы пока PotokThread не завершился, происходит утечка памяти, т.е. надо специально удалять объект. (Я так понимаю). Для этого надо проверить его валидность. Вариант 1 PotokThread * Pt=new PotokThread((QObject*)this); connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); Не делайте Pt членом класса, если deleteLater его грохнет, Вы остаетесь с уже удаленным указателем Вариант 2 (по-моему лучше) // connect(Pt , SIGNAL(finished()), Pt , SLOT(deleteLater())); Т.е. просто уберите/отключите эту строку. Остальное как у Вас, только в деструктор неплохо бы добавить Potok::~Potok() { if (Pt->IsRunning()) Pt->exit(); delete Pt; } Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 21, 2009, 12:21 Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль. Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы? Я же тебе писал по поводу сигналов linux. ???man signal Название: Re: Почему не срабатывает блок try? Отправлено: Igors от Август 21, 2009, 12:42 Нет, конечно, твой вариант завершения я попробовал, все работает без нареканий. Но вопрос более общий, как перехватить ситуацию в коде вообще, когда происходит прерывание программы по какой то ошибке, например деление на ноль. Мне предложили _set_se_translator, но что то я не могу найти его применение в линуксе. Есть много в инете по виндовс. На своем диске с линуксом я прошелся поиском, тоже ничего нет. Только wine и bost. Существует ли общее решение проблемы? Немного толку от перехвата общего "в программе произошла ошибка". Ну перехватили и что будете делать? Данные уже наверняка искалечены, остается показать окно с извинениями и выйти (да и то неизвестно живы ли еще окна). Имеет смысл перехватывать на каком-то участке, для этого есть try catch на любой платформе. Хотя перехват обращения по неверному адресу и возможен, это ошибка в программе которую надо исправлять, а не перехватыватьНазвание: Re: Почему не срабатывает блок try? Отправлено: Пантер от Август 21, 2009, 13:02 ИМХО, нужно изначально писать так, чтобы отпала надобность в try.
Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 21, 2009, 13:19 Немного толку от перехвата общего "в программе произошла ошибка". Ну перехватили и что будете делать? Данные уже наверняка искалечены, остается показать окно с извинениями и выйти (да и то неизвестно живы ли еще окна). Имеет смысл перехватывать на каком-то участке, для этого есть try catch на любой платформе. Хотя перехват обращения по неверному адресу и возможен, это ошибка в программе которую надо исправлять, а не перехватывать Такое поведение подходит для офисных приложений. ;)А если процесс управляет чем-то серьезным? Извиниться и выйти... Почему все данные должны быть искалечены? Часть - может быть, но не все! Например, перехватив подобные сигналы, можно в обработчике, сохранить важные параметры и спокойно умереть, а процесс-контроллер получит сигнал, что один из дочерних процессов убит и перезапустит его. Дальше считываем сохраненные параметры и продолжаем работу. Название: Re: Почему не срабатывает блок try? Отправлено: Rcus от Август 21, 2009, 13:31 А как вы узнаете что область памяти в которой хранятся ваши важные данные не испорчена уже? :) Ошибки доступа к мертвым указателям такие, ага.
Название: Re: Почему не срабатывает блок try? Отправлено: BRE от Август 21, 2009, 13:40 А как вы узнаете что область памяти в которой хранятся ваши важные данные не испорчена уже? :) Ошибки доступа к мертвым указателям такие, ага. При таком исходе, это хотя бы дает надежду на возможность сохранения данных, если разрушены, то разрушены.А проверить валидность данных в блоке можно, например, по присутствию меток и сигнатур или подсчетом контрольных сумм.... Название: Re: Почему не срабатывает блок try? Отправлено: a_n_y_a от Август 21, 2009, 13:44 Вопрос решился таким образомм:
void term_handler(int i) { printf ("Terminating\n"); exit(EXIT_SUCCESS); }; int main() { struct sigaction sa; sigset_t newset; sigemptyset(&newset); sa.sa_handler = term_handler; sigaction(SIGSEGV, &sa, 0); A *a=0; a->b=5; a->Pokaz(); ... Название: Re: Почему не срабатывает блок try? Отправлено: Igors от Август 21, 2009, 14:04 Вопрос решился таким образомм: Это будет работать и под Mac OSX. Но не на Вындоуз, так что говорить о кросс-платформенности не приходится void term_handler(int i) { printf ("Terminating\n"); exit(EXIT_SUCCESS); }; int main() { struct sigaction sa; sigset_t newset; sigemptyset(&newset); sa.sa_handler = term_handler; sigaction(SIGSEGV, &sa, 0); A *a=0; a->b=5; a->Pokaz(); ... Название: Re: Почему не срабатывает блок try? Отправлено: navrocky от Ноябрь 18, 2009, 17:15 Тем кому интересна эта тема, почитайте вот это - http://www.visualdata.ru/blog/109-segv-signal.html (http://www.visualdata.ru/blog/109-segv-signal.html).
Возможность нормально транслировать SIGSEGV и SIGFPE в языковые исключения и потом их обрабатывать есть. |