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

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

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

Сообщений: 11445


Просмотр профиля
« Ответ #15 : Апрель 17, 2012, 12:00 »

Полагаю, вы хотели сказать, что не все ситуации, ошибочные на первый взгляд, следует считать таковыми и, соответственно, использовать под них исключения.
Я хотел сказать простой вещь
Цитировать
     Механизм особых ситуаций является менее структурированным,
 чем такие локальные структуры управления как операторы if или for.
 Обычно он к тому же является не столь эффективным, если особая
 ситуация действительно возникла. Поэтому особые ситуации следует
 использовать только в том случае, когда нет хорошего решения с более
 традиционными управляющими структурами, или оно, вообще, невозможно.
Пока в этой теме - просто (нормальный) интерес "а не будет ли с исключениями лучше/проще". Ну пока не видно ни одного основания использовать исключения. Сделать конечно можно, но выгод это не даст
Записан
silart
Гость
« Ответ #16 : Апрель 17, 2012, 12:29 »

На самом деле мне близка позиция, высказанная товарищем Akon: обработка ошибок отделяется от основной логики программы. Я всегда использую такой подход в проектах С++. Где-то на самом верху стоит catch(), который ловит критические ошибки и выводит сообщения о типе ошибке, классе, методе, файле и строке, где произошла ошибка.
На локальном уровне генерируются и свои исключения, которые обрабатываются уровнем выше. Но обработка критических ошибок происходит все равно в одном месте - на самом верху. Исключение, брошенное где-то очень глубоко, начинает раскручивать стек и управление передается наверх в главный catch().

Таким же образом я хотел использовать и диалоги Qt. Некорректные действия пользователя в диалоге должны бросать исключение, которое должно обработаться внутри метода exec() - в теле цикла обработки событий. Обработчик  исключения должен вызывать скажем QMessageBox, а когда он будет закрыт, цикл обработки событий переходит к следующей итерации и диалог продолжает работать.
Записан
Bepec
Гость
« Ответ #17 : Апрель 17, 2012, 12:37 »

Мде... Мне одному кажется, что некоторые действия в диалоге, которые вызывают исключение, которое раскручивает стек и уходит на самый верх, показывает месседж бокс и далее опять идёт вниз - черезчур черезпопно?
Записан
silart
Гость
« Ответ #18 : Апрель 17, 2012, 12:50 »

Верес, стек раскручивается в данном случае не до самого верха, а до места вызова exec(). То есть обработчик ошибок диалога находится в месте вызова этого диалога.
Записан
Bepec
Гость
« Ответ #19 : Апрель 17, 2012, 13:15 »

Угу. Очень интересно конечно, но помоему очень и очень излишне.
Всёравно эта проверка будет производиться в диалоге. Там же будет посылаться исключение. Так что мешает на месте распальцевать польлзователю, в чём он неправ???

Без всяких "условных" проверок, без раскручивания стека, без описания обработчика ошибок класса (диалога), который вынесен за пределы класса...

Или я не понимаю всей серьёзности ваших диалогов. Там что, память пользователь мышкой проведя по лайнэдиту распиливает???
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Апрель 17, 2012, 13:49 »

Таким же образом я хотел использовать и диалоги Qt. Некорректные действия пользователя в диалоге должны бросать исключение, которое должно обработаться внутри метода exec() - в теле цикла обработки событий. Обработчик  исключения должен вызывать скажем QMessageBox, а когда он будет закрыт, цикл обработки событий переходит к следующей итерации и диалог продолжает работать.
Не видно удобного способа заключить обработчик в try. Также с событийной схемой/сигналами возможна масса заморочек - ведь то что уже попало в очередь может не будет убито исключением, или наоборот

обработка ошибок отделяется от основной логики программы. Я всегда использую такой подход в проектах С++. Где-то на самом верху стоит catch(), который ловит критические ошибки и выводит сообщения о типе ошибке, классе, методе, файле и строке, где произошла ошибка.
Конечно это звучит гордо - ну действительно, давайте отделим обработку ошибок! Улыбающийся Но если взглянуть непредвзято - а так ли уж это хорошо? Печатать файл/строку легко и приятно, а вот сообщения для пользователя - другой табак. Выскочив наверх мы потеряли "контекст", по-простому говоря: многое что нам надо для показа в MessageBox у нас в локальных переменных и/или др классах. И теперь придется переть это все наверх, обычно раздувая классы исключений
Записан
Bepec
Гость
« Ответ #21 : Апрель 17, 2012, 14:28 »

Наверх всё это не вынести. И потому получается рекурсия:

Вызов диалога -> ошибка -> ексцепшен -> выход наверх -> вызов данных из диалога -> ексцепшен -> выход наверх -> вызов данных из диалога -> -//- -//-

Ну а чтобы все данные из диалога вытащить, нужно как минимум их открыть(что опять таки плохо), либо писать свои функции вывода  указателя/лей/информации.

Задумайтесь людиии, вы пытаетесь болезнь отделить от больного. Вместо лечения больного.

оффтоп:
П - пациент, Д - доктор, ГВ - главврач
П - Доктор, у меня рак лёгких!
Д - Сейчас вызовем главного врача, он у нас хирург, всё будет хорошо. *делает звонок*
*проходит 15 минут, приходит главврач*
ГВ- Вырежем у вас лёгкие, заодно печень, почки и глаз. Проверим, поставим диагноз и вылечим.
*через день на могилке*
ГВ- Мы бы вылечили его, но нам нехватило кишечника, а он уже скончался...
Д - В следующий раз кишечник сразу возьмём Подмигивающий
Записан
Akon
Гость
« Ответ #22 : Апрель 17, 2012, 16:09 »

Верес:
Цитировать
Угу. Очень интересно конечно, но помоему очень и очень излишне.
Всёравно эта проверка будет производиться в диалоге. Там же будет посылаться исключение. Так что мешает на месте распальцевать польлзователю, в чём он неправ???

Без всяких "условных" проверок, без раскручивания стека, без описания обработчика ошибок класса (диалога), который вынесен за пределы класса...

Или я не понимаю всей серьёзности ваших диалогов. Там что, память пользователь мышкой проведя по лайнэдиту распиливает???
Вы не понимаете не серьезности диалогов, а серьезности подхода  Улыбающийся В диалоге вы выбрасываете исключение со всей необходимой информацией, а "распальцовку" делает не диалог, а код, находящийся выше по стеку. Мне лень в каждом диалоге или окне каждого проекта писать стереотипный код с MessageBox-ом, за меня это сделает обработчик исключения уровнем повыше.

Igors:
Цитировать
Выскочив наверх мы потеряли "контекст", по-простому говоря: многое что нам надо для показа в MessageBox у нас в локальных переменных и/или др классах. И теперь придется переть это все наверх, обычно раздувая классы исключений
Контекст, как вы заметили, сохраняется в исключении. А на самом верху используется всего то exception.what(). Раздутый класс исключения - это о чем?

Цитировать
Не видно удобного способа заключить обработчик в try.
QCoreApplication::notify()

Цитировать
Также с событийной схемой/сигналами возможна масса заморочек - ведь то что уже попало в очередь может не будет убито исключением, или наоборот
Верно, исключения в слотах не поддерживаются.

silart:
В Qt нет такой удобной реализации, как в VCL. Как я уже говорил, чтобы ее заиметь нужно:
1. Поработать над QCoreApplication::notify(), т.е. установить обработчик верхнего уровня для всех событий.
2. Изменить код вызова слотов в QtCore и перекомпилировать либу (непрактично).

Код, который вы привели в первом посте
Код:
try
{
   MyDialog dlg(this);
   dlg.exec();
}
catch(const std::exception& e)
{
// Вывод сообщения
}
это не то, как, вы сами же и заметили
Цитировать
Очевидно, что для этого нужно установить try {} catch(...) внутри метода exec() где-то в теле цикла обработки сообщений.
Записан
Akon
Гость
« Ответ #23 : Апрель 17, 2012, 16:19 »

Вот пример:

// MainWindow.h
Код:
#include <QtGui/QDialog>
#include <stdexcept>

// Dialog

class Dialog : public QDialog
{
Q_OBJECT

public:
Dialog()
{
QMetaObject::invokeMethod(this, "handler", Qt::QueuedConnection);
}

private:
Q_SLOT void handler()
{
throw std::runtime_error("Error message for user");
}
};

// Main.cpp
Код:
#include "MainWindow.h"
#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
#include <stdexcept>

// Application

class Application : public QApplication
{
public:
Application(int argc, char *argv[]) : QApplication(argc, argv)
{
}

protected:
virtual bool notify(QObject * o, QEvent * e)
{
try {
return QApplication::notify(o, e);
}
catch (const std::exception& e) {
QMessageBox::critical(0, QApplication::instance()->applicationName(),
e.what(), QMessageBox::Ok, QMessageBox::NoButton);
}
catch (...) {
QMessageBox::critical(0, QApplication::instance()->applicationName(),
"Unexpected application error", QMessageBox::Ok, QMessageBox::NoButton);
}

return false;
}
};

// Entry

int main(int argc, char *argv[])
{
Application app(argc, argv);
Dialog dialog;
dialog.exec();  // исключение выбрасывается здесь, здесь же оно и обрабатывается
return 0;
}
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #24 : Апрель 17, 2012, 16:58 »

В диалоге вы выбрасываете исключение со всей необходимой информацией, а "распальцовку" делает не диалог, а код, находящийся выше по стеку. Мне лень в каждом диалоге или окне каждого проекта писать стереотипный код с MessageBox-ом, за меня это сделает обработчик исключения уровнем повыше.
Сравнивая 2 варианта
Код
C++ (Qt)
if (!Validate()) throw MyException(..);
или
if (!Validate()) return ShowError(..);
 
я не вижу никаких преимуществ первого. Что же "распальцевало" исключение? Да по сути ничего, показало месягу с тем что дали (e.what), с тем же успехом могу сделать это просто ф-цией/методом. А львиная доля работы с ошибками часто именно в подготовке этого what. С этой точки зрения вынесение обработчика наверх ничего не дает
Записан
alexis031182
Гость
« Ответ #25 : Апрель 17, 2012, 17:03 »

Меня интересует вопрос: а что получится, если диалог, окно, да просто виджет/объект (QObject) будет создан через new, да при том без указателя на родителя (this)? Как узнать в обработчике исключения, что объект надо удалить, если он выбивается из ряда других себе подобных и создан динамически?

В этой теме, как я понял, исключения рассматриваются не с точки зрения критических ошибок, а просто как средство замены нативных системы событий и сигнал/слотов, правильно?
Записан
Bepec
Гость
« Ответ #26 : Апрель 17, 2012, 19:51 »

Угу. Люди поняли - вот он стереотип счастья. Вместо написания 1 (одной) проверки, можно отослать наверх исключение с багажником необходимой информации. И всё ради 1 месседж бокса.

Боженька, прошу тебя  никогда мне не посылай такого чужого кода!!!

Записан
V1KT0P
Гость
« Ответ #27 : Апрель 18, 2012, 06:49 »

Угу. Люди поняли - вот он стереотип счастья. Вместо написания 1 (одной) проверки, можно отослать наверх исключение с багажником необходимой информации. И всё ради 1 месседж бокса.

Боженька, прошу тебя  никогда мне не посылай такого чужого кода!!!
Я полностью с тобой согласен. Меня особо бесит IBPP, там исключения попихали ку-да только можно. И получается простыня из try catch на несколько экранов. Попробовал обойтись без обертки, не так удобно зато никакой каши из-за исключений, да и гибкость повысилась. Если мне например на неудачный запрос в базу надо откатить до предыдущего состояния и повторить без него, то без исключений там элементарно. С исключениями же либо использовать их 100500 штук да еще и с переменными, которые вернут последнее состояние из исключений, получается такая жопа.
Я считаю что исключения должны использоваться исходя из их названия - в исключительных случаях которые по каким-то причинам не предусмотрел программист и дальнейшая нормальная работа не возможна.
Записан
Bepec
Гость
« Ответ #28 : Апрель 18, 2012, 06:54 »

Мне вот исключения представляются просто - критическое оповещение, когда программа уже летит в тартарары.

И выдавать оно должно только критичную информацию. Типа "чувак у тебя тут 20-й элемент в 5-элементном массиве запрашивается".

И уж точно - никогда не обрадуешься зависимости исключений в вышестоящих классах и нижестоящих Подмигивающий
« Последнее редактирование: Апрель 18, 2012, 06:57 от Bepec » Записан
Akon
Гость
« Ответ #29 : Апрель 18, 2012, 07:49 »

Цитировать
Сравнивая 2 варианта
Код
C++ (Qt)
if (!Validate()) throw MyException(..);
или
if (!Validate()) return ShowError(..);
 
я не вижу никаких преимуществ первого. Что же "распальцевало" исключение? Да по сути ничего, показало месягу с тем что дали (e.what), с тем же успехом могу сделать это просто ф-цией/методом. А львиная доля работы с ошибками часто именно в подготовке этого what. С этой точки зрения вынесение обработчика наверх ничего не дает
1. Хоть сколько нибудь серьезная программа никогда не будет размещать бизнес логику (Validate) в слое GUI.
2. В слое бизнес логики вы не можете использовать if (!Validate()) return ShowError(..); поскольку ShowError - это конкретное действие, допустим MessageBox. А если консольная прога? Там не нужен MessageBox. Получается, что бизнес логика зависит от типа приложения. Да, можно абстрагироваться от конкретного вывода ошибки, но получается дополнительная зависимость бизнес логики, которой нет в случае исключений.
3. Нет механизма структурированной обработки ошибки (в нетривиальной бизнес логике это важнейший аспект).

Люди, негативно относящиеся к исключениям, в большинстве своем просто не понимают назначения этого механизма. Дискутировать с ними молоперспективно (да и попросту неинтересно).

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


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