Подтвердить что ты не робот

Как поймать исключения в Qt?

try
{  // `count()` throws exception
  connect(thread, SIGNAL(started()), engine, SLOT(count()));  
}
catch(const X& e)
{}

Как и в Qt-5, я получаю следующую ошибку:

Qt поймал исключение, выведенное из обработчика события. Бросание исключения из обработчика события не поддерживаются в Qt. Вы не должны допускать каких-либо исключений, распространяемых через Qt-код. Если это невозможно, в Qt 5 вы должны, по крайней мере, повторно выполнить QCoreApplication::notify() и поймать все исключения там.

Если я не могу поймать исключения обычным способом, как показано выше, тогда где мы должны их поймать?

4b9b3361

Ответ 1

где я должен его поймать?

Именно поэтому Qt не поддерживает бросание исключений через соединения сигналов/слотов. Если вы попробуете, вы увидите следующее сообщение:

Qt поймал исключение, выведенное из обработчика события. Бросание исключения из обработчика события не поддерживаются в Qt. Вы должны reimplement QApplication:: notify() и поймать все исключения там.

Как он упоминает, можно подклассифицировать QApplication и поймать ваше исключение, но это будет очень раздражающим способом обработки вещей.

Если возможно, я бы рекомендовал пересчитать количество, чтобы оно не выбрасывалось.


Что делать, если вы не можете переписать count()?

Например, что, если count() является частью функции в сторонней библиотеке, которую вы используете?

Нет ни одного слота в любой официальной библиотеке Qt, поэтому, если вы используете стороннюю библиотеку с слотом, который бросает, это, вероятно, признак того, что это не хорошая библиотека. Если вы хотите использовать его в любом случае, я рекомендую вместо этого перехватить его в QApplication::notify, вместо этого вы создадите адаптер.

Что это значит? Сначала создайте объект, который возьмет ваш отрывочный сторонний объект в конструкторе. В нем напишите слот, который завершает вызов слоту метания с помощью блока try/catch. Теперь вместо того, чтобы подключаться к отрывочному пространству сторонних объектов, подключитесь к новому слою для создания объектов.

Выполнение обхода исключения таким образом связывает связанный код и предотвращает заполнение QApplication::notify кучей несвязанных блоков try/catch, если вы сталкиваетесь с более чем одной из этих проблемных функций.

Например:

class BadCounter {
Q_OBJECT
public slots:
  void count() { throw CounterError("unable to count"); }
};

class CounterAdaptor {
Q_OBJECT
  BadCounter* counter_;
public:
  CounterAdaptor(BadCounter* counter) {
    counter_ = counter;
  }
public slots:
  void count() {
    try {
      counter_->count();
    } catch (const CounterError& e) {
      std::cerr << e.what() << std::endl;
    }
  }
};

int main() {
  BadCounter engine;
  CounterAdaptor adaptor(&engine);
  QThread* thread = new QThread();
  connect(thread,SIGNAL(started()),&adaptor,SLOT(count())); 
  thread.start();
  ... // etc...
  delete thread;
}

Что делать, если вы хотите обрабатывать то, что можно выбросить из любого места?

Очевидным примером такого рода глобальной озабоченности является неожиданное исключение. Ошибки могут произойти где угодно. Было бы желательно записать как можно больше подробностей о событии, чтобы можно было определить и исправить причину. В этом случае вы захотите повторно реализовать QApplication::notify в своем подклассе, как показано в jichi answer. Использование глобального обработчика для глобальных проблем вполне разумно.

Ответ 2

Если кому-то нужен код примера для переопределения QApplication:: notify, я получил его отсюда (на японском языке): http://www.02.246.ne.jp/~torutk/cxx/qt/QtMemo.html p >

#include "MyApplication.h"
#include <exception>

MyApplication::MyApplication(int& argc, char** argv) :
  QApplication(argc, argv) {}

bool MyApplication::notify(QObject* receiver, QEvent* event) {
  bool done = true;
  try {
    done = QApplication::notify(receiver, event);
  } catch (const std::exception& ex) {
    // ログや何らかの回復処理
  } catch (...) {
    // ログや何らかの回復処理
  }
  return done;
} 

Ответ 3

Вы можете попробовать это для примера, чтобы увидеть, что ваше решение хорошо:

int f()
{
    throw 1;
    return 5;
}

void g(int x)
{
    cout << x << endl;
}

int main()
{
    try {
            g(f());
    }catch(int)
    {
        cout << "Caught exception" << endl;
    }
}