Russian Qt Forum

Qt => Вопросы новичков => Тема начата: __Heaven__ от Июнь 15, 2015, 20:07



Название: Как пользоваться исключениями
Отправлено: __Heaven__ от Июнь 15, 2015, 20:07
Привет, друзья!
Я никогда не пользовался исключениями, но хотел бы научиться.
Как они работают и синтаксис я понял. Не ясно вот что:
Что принято бросать в какой ситуации? Допустим, у меня нет указанного файла, что бросать?
Есть ли смысл наследоваться от стандартных классов, QException. Нужно ли придумывать и указывать код ошибки?
Оно нужное дело вообще или можно статусами обойтись?


Название: Re: Как пользоваться исключениями
Отправлено: Авварон от Июнь 15, 2015, 20:20
Не используйте исключения в кутешном коде.


Название: Re: Как пользоваться исключениями
Отправлено: Igors от Июнь 16, 2015, 09:27
Оно нужное дело вообще или можно статусами обойтись?
Однозначно нужное, хотя бы потому что это штатное средство языка. А вот насколько - есть разные мнения. Я стараюсь всегда обойтись кодом ошибки до тех пор пока необходимость исключений не станет очевидной. Другие наоборот, используют исключения при первой возможности.

Что принято бросать в какой ситуации? Допустим, у меня нет указанного файла, что бросать?
Есть ли смысл наследоваться от стандартных классов, QException. Нужно ли придумывать и указывать код ошибки?
Да на все вопросы. Опять-таки насколько нужно размазывать классы исключений - дело вкуса/стиля. Пример
Код
C++ (Qt)
if (что-то не связалось)
throw MyException("Line %d: invalid syntax", lineNomer);
 
Испускающий не знает имени файла при чтении которого произошла ошибка - зато прекрасно знает что случилось
Код
C++ (Qt)
try {
DoReadFile(...);
}
catch (MyException & e) {
ShowError("Error reading " + fileName + ": "  + e.errorText());
}
catch (...) {
ShowError("Unknown error reading " + fileName);
}
Ловящий наоборот, имя файла знает, но что конкретно случилось - нет. Вот и комбинируйте


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 19, 2015, 15:30
Я широко использую исключения в Qt-приложениях. Ho! Нужно понимать как будет проходить исключение через код Qt, и что этот код делает при наличии исключения. Во многих случаях код Qt просто не рассчитан на возможное наличие исключения, и вы можете получить утечку памяти, крах, или неопределенное поведение.

Одни участки Qt-кода могут быть адаптированы (перекрытие виртуальных методов) вами для корректной работы с исключениями, например, если вы выбросите исключение из QAbstractItemModel::setData(), то у вас завалится любой делегат из Qt, но вы можете сделать свой класс делегата с соответствующей функцией.

Другие - могут быть относительно легко адаптированы с помощью патчинга сорцов Qt с последующей перекомпиляцией, например, я делал патчинг QObject::activate() с целью выбрасывать исключения из слотов с дефолтным показом сообщения и без разрыва вызова цепочки слотов.

С третьими - по большому счету никак.

В основном, исключения больше пронизывают ваш код, чем Qt. Наследовать исключения лучше от std::exception, все ошибки времени выполнения - от std::runtime_error. При использовании исключений вместа кода ошибки (категории кода ошибки) используется тип исключения. Все std-исключения минимально функциональны (хотя их функций достаточно во вногих случаях), например, нет метода clone() или цепочки вложенных исключений. Также, в boost есть кроссплатформенная либа для работы с системыми (OS API) ошибками через исключения.

P.S.
Исключение - это просто альтернативное ветвление алгоритма с побочными (нужными) действиями. Ничего особенного.



Название: Re: Как пользоваться исключениями
Отправлено: Авварон от Июнь 19, 2015, 18:15
Во многих случаях код Qt просто не рассчитан на возможное наличие исключения, и вы можете получить утечку памяти, крах, или неопределенное поведение.

Очень удобно, да:(


Название: Re: Как пользоваться исключениями
Отправлено: __Heaven__ от Июнь 21, 2015, 12:33
спасибо. Достаточно подробно.


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 27, 2015, 13:35
Не используйте исключения в кутешном коде.
А как действовать в случае использования сторонней библиотеки, в которой на каждый чих генерируется исключение?
Я столкнулся с этим MQTT C++ Client. Пробовал вызовы функций библиотеки делать через обработку всех исключений, например:
Код:
try{
  client.subscribe(subTopic, QOS, nullptr, subListener);
}catch(...){
}
не помогает, программа валится.


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 27, 2015, 16:26
Потому что ABI получился различным. Что в либе (dwarf, sjlj), и что в программе?


Название: Re: Как пользоваться исключениями
Отправлено: Igors от Июнь 27, 2015, 17:21
Потому что ABI получился различным. Что в либе (dwarf, sjlj), и что в программе?
Вот когда знатоки бросают такие фразы... ну я прямо теряюсь :) Вот мои скудные познания

ABI - набор правил/соглашений по вызовам (типа что на каком регистре ожидает callee). Как он может "получаться" различным ???  Либа может быть совместима по ABI или нет - и тогда ее никак не приспособить.

dwarf - видел в установках, формат отладочной информации

sjlj - никогда не слыхал о таком

Растолкуйте плиз что я не так понимаю. Спасибо


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 27, 2015, 18:02
Когда вы пишите try/catch компилятор создает дополнительные служебные структуры данных, помещаемые на стеке (или еще в каких секциях). Если исключение переходит  границу модулей, то формат этих структур должен быть идентичен для этих модулей. Для поддержки исключений компилятор может использовать разные механизмы, например, MSVC использует SEH - это вообще механизм ОС. В этом случае, например, throw в конечном счете трансформируется в вызов API RaiseException, а catch - в соостветствующие фильтры __except. Как вы понимаете, это все ABI.


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 27, 2015, 22:44
Когда вы пишите try/catch компилятор создает дополнительные служебные структуры данных, помещаемые на стеке (или еще в каких секциях). ...
Круто. И библиотека, и программа, использующая библиотеку, собраны одним компилятором - mingw.


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 27, 2015, 23:30
Вы сами собирали?


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 28, 2015, 14:13
Вы сами собирали?
Да.


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 28, 2015, 14:56
А при каком типе исключения валится? Если вставить в самое начало ф-ии
client.subscribe(subTopic, QOS, nullptr, subListener);
throw std::exception();
что будет?


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 28, 2015, 17:00
На этом типе и валится:
terminate called after throwing an instance of 'mqtt::exception'
  what():  std::exception

Но сейчас вставлю в функцию throw, посмотрим.
upd: все то же самое.


Название: Re: Как пользоваться исключениями
Отправлено: Igors от Июнь 28, 2015, 17:28
На этом типе и валится:
terminate called after throwing an instance of 'mqtt::exception'
  what():  std::exception

Но сейчас вставлю в функцию throw, посмотрим.
upd: все то же самое.
Был в похожей ситуевине (вот валится на любом испускании), методом втыка нашел что помогает выключить "dead strip code" (ну это в терминах Xcode, как в mingw не в курсе). Т.е. просто баг компилятора (точнее линкера).

Конечно шансов что у Вас то же самое очень мало. Самое мерзкое в этих исключениях - что разобраться "логически" (не побоюсь этого слова  :)) - просто не видно как. Отладчик или вообще потерял стек или наводит на какие-то исходники куда Макар телят не гонял. Такие залеты отливаются в неск дней "плясок с бубном", и приходят соображения типа "та ну его нафиг, пусть будет менее стройно зато с отладкой без проблем".


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 28, 2015, 17:54
В принципе, библиотека не очень большая. Можно все исключения заменить на возврат кодов.
Наверное, так и сделаю потом. Не очень удобно - с каждой новой версией придется вносить правки.


Название: Re: Как пользоваться исключениями
Отправлено: Akon от Июнь 29, 2015, 09:33
Ну хорошо, а если в библиотеке написать свою функцию и оттуда выбросить исключение?

Да проблема с флагами сборки. Заменять исключения на коды ошибок считаю не вариант.


Название: Re: Как пользоваться исключениями
Отправлено: sergek от Июнь 29, 2015, 12:20
Да проблема с флагами сборки. Заменять исключения на коды ошибок считаю не вариант.
Одинаково все. По крайней мере, что касается исключений. Вот проекты.
В принципе, могу и исходники, но вам это будет гиморно - нужно установить брокер, собрать библиотеки (C и C++).