Russian Qt Forum
Ноябрь 05, 2024, 22:08 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5   Вниз
  Печать  
Автор Тема: C++ Exceptions и Qt  (Прочитано 34689 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #45 : Апрель 18, 2012, 16:37 »

Верес, emit отличается от throw тем, что код после throw, в случае его срабатывания, не исполняется. Когда бросаем throw, начинается раскрутка стека, в результате которой вызываются деструкторы всех созданных в стеке объектов и утечка ресурсов не происходит.
Когда же вы вызываете emit, это приводит к вызову всех слотов, и после этого код стоящий после emit будет выполняться далее.
Ну а почему дальнейшее выполнение "обязательно плохо"? Это зависит от задачи, напр в примере с диалогом ввода я лично ничего плохого не вижу.

Ну если уж попали на любителей исключений, то такой вопрос: а что будет если при пресловутой "раскрутке стека" произойдет еще одно исключение?
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #46 : Апрель 18, 2012, 16:44 »

Ну если уж попали на любителей исключений, то такой вопрос: а что будет если при пресловутой "раскрутке стека" произойдет еще одно исключение?

Деструкторы не должны кидать исключения, если кидают - это надо исправлять.
Записан

Гугль в помощь
V1KT0P
Гость
« Ответ #47 : Апрель 18, 2012, 16:45 »

Ну дык и ловить исключения тоже можно забыть или одно какое-то исключение пропустить и тоже ничего хорошего не будет. Я себе плохо представляю как можно на исключениях строить логику, это-же получится простыня из catch-ей. Выделили память в куче в функции и вызвали другую функцию, она бросила исключения стек свернулся а память в куче так занята и осталась. Исключение это goto, но только не скованный пределом функции.

Все оттого, что реально их не использовали. У меня один try/catch на самом верху в notify, который рапортует об ошибке (хотя теперь для надежности еще оборачиваю слоты). В остальном я о них не думаю, просто пишу код. От утечек спасают смарт-поинтеры, кутэшное владение QObject и RAII. Стараюсь вообще обычные указатели не использовать. Исключение - хитрые оптимизации, но такого кода у меня очень мало.
Да сам я логику никогда на исключениях не строил. Но вот библиотекой IBPP которая таки напичкана исключениями до сих пор пользуюсь так вот обычная функция которая всего-то должна выполнить запросы превращается в кашу из try catch. Когда же потребовалось чуть больше гибкости я выбросил библиотеку и использовал АПИ напрямую, так код получился просто шикарным. Я не за то чтоб полностью отказаться от исключений. Меня бесит только чрезмерное их употребление, особенно там где без этого можно обойтись.
Например надо записать данные в файл. Перед записью проверяется наличие файла и тут вопрос: На кой кидать исключение которое вызовет функцию создания файла а затем выполнить функцию записи? Не проще ли сперва в самой функции вызвать функцию создания файла и уж если она не сработает и больше сделать нечего то да тут уже надо бросать исключение ибо выхода нет. Но вот как ветвление использовать исключение это слишком. Это ты своем коде легко разбираешься, а вот если тебе дадут большой проект где ветвления будут через исключения, посмотрим как ты будешь там ориентироваться.
Записан
silart
Гость
« Ответ #48 : Апрель 18, 2012, 16:59 »

А я без notify() обрабатывал исключения следующим образом:

Код:
	QApplication a(argc, argv);
PlatformManager pmgr(NULL, Qt::Window);

try
{
pmgr.show();
a.exec();
}
catch(ml::Exception& e)
{
ml::qt::ErrorBoxDialog::show("Калибратор", e.title().c_str(), e.what().c_str(), &pmgr);

return 0;
}

navrocky , что вы думаете по этому поводу?
Записан
V1KT0P
Гость
« Ответ #49 : Апрель 18, 2012, 17:02 »

navrocky , что вы думаете по этому поводу?
Ну это совсем не то про что идет речь. Речь идет про использование исключений для ветвлений логики, у вас же просто информирование про ошибку и закрытие программы.
Записан
silart
Гость
« Ответ #50 : Апрель 18, 2012, 17:06 »

Просто шла речь про то, что notify() недокументирован на предмет использования исключений.
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #51 : Апрель 18, 2012, 18:25 »

Перед записью проверяется наличие файла и тут вопрос: На кой кидать исключение которое вызовет функцию создания файла а затем выполнить функцию записи? Не проще ли сперва в самой функции вызвать функцию создания файла и уж если она не сработает и больше сделать нечего то да тут уже надо бросать исключение ибо выхода нет.
Да, за такое использование исключений надо по рукам бить. Надо проверить что файл есть, если нет то создать, если не создается - кинуть исключение.
Записан

Гугль в помощь
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #52 : Апрель 18, 2012, 19:07 »

А я без notify() обрабатывал исключения следующим образом:

Код:
	QApplication a(argc, argv);
PlatformManager pmgr(NULL, Qt::Window);

try
{
pmgr.show();
a.exec();
}
catch(ml::Exception& e)
{
ml::qt::ErrorBoxDialog::show("Калибратор", e.title().c_str(), e.what().c_str(), &pmgr);

return 0;
}

navrocky , что вы думаете по этому поводу?

Ну как вариант сойдет. Но помните что шансы словить исключение этим catche'м не стопроцентные. Т.к. исключение будет проходить через кутэшную прослойку, что может привести к различным эффектам.
У меня, например, был случай когда так исключения не ловились и программа завершалась по abort() как это происходит, когда кидаешь исключение и не ловишь его. С 3-м кутэ и с 4-ым.
Записан

Гугль в помощь
Bepec
Гость
« Ответ #53 : Апрель 18, 2012, 21:04 »

Угу. Куте с радостью пропускает некоторые исключения и вызывает свою (умную) реакцию.  Подмигивающий

Мне просто интересно, что может испортить выполнение дальнейшего кода?

Например в данном случае(нажатие на ок)
Код:
if (ui.spinBox->value() < 20) // вот это ошибочная проверочка
{
emit error(); // или окно с ошибочкой
return;
}
int x[20];
x[ui.spinBox->value()] = 0;
Записан
silart
Гость
« Ответ #54 : Апрель 19, 2012, 05:15 »

Ну как вариант сойдет. Но помните что шансы словить исключение этим catche'м не стопроцентные. Т.к. исключение будет проходить через кутэшную прослойку, что может привести к различным эффектам.
У меня, например, был случай когда так исключения не ловились и программа завершалась по abort() как это происходит, когда кидаешь исключение и не ловишь его. С 3-м кутэ и с 4-ым.

Может быть это связано с тем, что Qt может быть собрана с ключем no-exceptions, и в этом случае какой-нибудь макрос везде устанавливает catch(...) {}. Вот исключения и не проходят. C++ то никто еще не отменял!  Подмигивающий
Но в моем случае это не страшно, потому что я сам собираю Qt.
Записан
silart
Гость
« Ответ #55 : Апрель 19, 2012, 05:30 »

Мне просто интересно, что может испортить выполнение дальнейшего кода?

Например в данном случае(нажатие на ок)
Код:
if (ui.spinBox->value() < 20) // вот это ошибочная проверочка
{
emit error(); // или окно с ошибочкой
return;
}
int x[20];
x[ui.spinBox->value()] = 0;

Верес, ваш код
Код:
emit error();
return;

отличается от кода
Код:
throw std::logic_error("Error");
тем, что после вызова слотов вы ставите return. То есть вы пытаетесь имитировать механизм исключений. В таком виде ваш код неявно вызовет только деструкторы объектов находящиеся в контексте вашего слота. Если ваш слот будет вызван из другой функции, а эта функция в свою очередь из другой, а если у этих функций есть стековые объекты в своих контекстах, их деструкторы вызваны не будут и произойдет утечка ресурсов.

Ваша функция после вызова emit вернет управление как ни в чем не бывало, а дальнейшая логика работы программы пойдет по своему обычному пути, хотя внутри вашего слота возникли проблемы.

Выброс исключения в контексте какой-то внутренней функции вызывает раскрутку стека и все стековые объекты корректно удалятся, а логика работы программы пойдет уже по альтернативному пути, т. е. дальнейшие действия (стоящие за вызовом вашего сбойного слота) выполнены не будут. Благодаря этому вы избавитесь от ошибок, возникающих время от времени то тут то там.
Вот в чем смысл использования исключений.
Записан
Bepec
Гость
« Ответ #56 : Апрель 19, 2012, 07:03 »

Кхм. То есть у вас, если диалог выдаст ошибку валидации, вы вызовете деструкторы диалога, деструкторы его родителя виджета и прочего, вплоть до всех созданных объектов?

Помоему у вас с логикой не то.

Моя конструкция с return НЕ ДОПУСКАЕТ возникновения исключительной ситуации Подмигивающий Как бы ты не изощрялся, проверку пробить может только порча памяти в моей же программе, а от этого не спасёт даже твоё исключение Подмигивающий

А благодаря логической структуре программы, нет необходимости в "убиении" всех свидетелей этого "позора".

Да, это аналог исключения, ибо это слабая пародия на исключительную ситуацию. Но напомню - пародия, которая не нуждается в отсылке куда-то, кого-то, с каким-то параметром, какого-то эксепшена какого-то типа. И не выходя за рамки класса, выдавшего предупреждение (не ошибку), предупреждение будет должным образом обработано.

Да и действительно, приведите пожалуйста свой код "среднего" try/catch в ваших программах. Хочется оценить величину простыни и понятность кода.
Записан
Akon
Гость
« Ответ #57 : Апрель 19, 2012, 07:26 »

Цитировать
Да и есть один аргумент. Если Qt пишется без учета исключений, а прослойка в обработчике евентов там довольно жирная - значит есть довольно большой шанс, что как минимум могут ресурсы утечь, что-то недоинициализируется... Т.к. это недокументированная возможность ловли исключений через QCoreApplication::notify, не исключено, что если сегодня оно не сегфолтится и не течет, то завтра вполне это может случиться.
Да, жирная прослойка меня тоже очень насторожила, но вот код из QEventLoop::exec():
Код:
int QEventLoop::exec(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    if (d->threadData->quitNow)
        return -1;

    if (d->inExec) {
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
        return -1;
    }
    d->inExec = true;
    d->exit = false;
    ++d->threadData->loopLevel;
    d->threadData->eventLoops.push(this);

    // remove posted quit events when entering a new event loop
    QCoreApplication *app = QCoreApplication::instance();
    if (app && app->thread() == thread())
        QCoreApplication::removePostedEvents(app, QEvent::Quit);

#if defined(QT_NO_EXCEPTIONS)
    while (!d->exit)
        processEvents(flags | WaitForMoreEvents | EventLoopExec);
#else
    try {
        while (!d->exit)
            processEvents(flags | WaitForMoreEvents | EventLoopExec);
    } catch (...) {
        qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
                 "exceptions from an event handler is not supported in Qt. You must\n"
                 "reimplement QApplication::notify() and catch all exceptions there.\n");

        // copied from below
        QEventLoop *eventLoop = d->threadData->eventLoops.pop();
        Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
        Q_UNUSED(eventLoop); // --release warning
        d->inExec = false;
        --d->threadData->loopLevel;

        throw;
    }
#endif

    // copied above
    QEventLoop *eventLoop = d->threadData->eventLoops.pop();
    Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
    Q_UNUSED(eventLoop); // --release warning
    d->inExec = false;
    --d->threadData->loopLevel;

    return d->returnCode;
}
Как видно, в #else ветке условия #if defined(QT_NO_EXCEPTIONS) мы имеем варнинг "Qt has caught ...", по которому можно судить, что возможность использования исключений есть, и прослойка Qt будет exception safe. Хотя, я реально exception safety не проверял.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #58 : Апрель 19, 2012, 13:03 »

Выброс исключения в контексте какой-то внутренней функции вызывает раскрутку стека и все стековые объекты корректно удалятся, а логика работы программы пойдет уже по альтернативному пути, т. е. дальнейшие действия (стоящие за вызовом вашего сбойного слота) выполнены не будут. Благодаря этому вы избавитесь от ошибок, возникающих время от времени то тут то там.
Вот в чем смысл использования исключений.
Посмотрите что стоит в catch в исходнике exec которые привел Akon. Чудесная "раскрутка" почему-то не сделала (пере)установку inExec и loopLevel, и приложение рухнет если убрать это из catch. Также заметим что с пере-испусканием throw утеряна вся информация об исключении.

А тот "альтернативный путь" далеко не всегда возможен и/или желателен. Я не против исключений, но в меру, а то судя по Вашим словам - ну прямо "искусственный интеллект"  Улыбающийся
Записан
Bepec
Гость
« Ответ #59 : Апрель 19, 2012, 13:19 »

Нейросеть + ексепшены = скайнет.

То-то у него постоянно глючило всё. То робот не услышит, то летает неправильно, то ездит с неположенной скоростью Подмигивающий
Записан
Страниц: 1 2 3 [4] 5   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.073 секунд. Запросов: 23.