Qt中类层次结构的异常处理

时间:2013-12-08 14:30:41

标签: c++ qt exception-handling

我正在为Windows平台开发Qt应用程序。在类层次结构中使用异常处理时遇到问题。

我在类A的函数中实例化了B类对象。当由于某种原因,从类B抛出异常(并且未在类B中捕获)时,它不会被捕获到类A中(适当的尝试 - catch块存在于A类中,而应用程序崩溃则显示某些特定于Windows的错误。类层次结构中的这种类型的try-catch机制在Java中完全正常。

示例:

这是ClassA的一段代码,用于实现ClassB的对象(Qt Dialog)

void Class A::on_pbCallB_clicked()
{
    try
    {
        objClassB = new ClassB();
        objClassB->show();
    }
    catch(QString *strExceptionMsg)
    {
        QMessageBox::critical(this,"Error",*strExceptionMsg);
        exit(1);
    }
    catch(...)
    {
        QMessageBox::critical(this,"Error","Uknown Error");
        exit(1);
    }
}

当显示ClassB对话框并按下对话框上的按钮时,会调用以下代码:

void ClassB::on_pbThrowExp_clicked()
{
    try
    {
        throw (new QString("Throwing Exception !"));
    }
    catch(QString *strExceptionMsg)
    {
        throw strExceptionMsg;
    }
    catch(...)
    {
        throw (new QString("Unknown Error"));
    }
}

这会引发一个异常,它会在ClassB的函数中捕获,但是当它被进一步抛出时,它不会被ClassA捕获(从objClassB实例化的地方)并且整个应用程序崩溃。

我尝试了一个解决方案,我已经重新实现了QApplication的通知方法,其中,如果没有捕到任何地方,从应用程序某处抛出的异常将被重新实现的notify方法捕获。但这样做并不能阻止应用程序关闭。

请确认在Qt / C ++中是否可以实现这一点,如果没有,请指出我在Qt中的替代方案(如果有的话)。

1 个答案:

答案 0 :(得分:4)

这是一个老问题,但由于可能还有人试图将Qt与异常处理结合起来,以下是一个对我有用的解决方案。它需要c ++ 11支持。

application.hpp:

#ifndef APPLICATION_HPP
#define APPLICATION_HPP

#include <QApplication>
#include <exception>

///
/// This class catches any exceptions thrown inside proc()
/// and shows them using the message() function.
/// The virtual message() function can be overriden to customize
/// how the messages are shown. The default implementation
/// shows them using QMessageBox.
///
class Application: public QApplication
{
public:
    Application(int& argc, char* argv[]);
    bool notify(QObject* receiver, QEvent* event);

    virtual int proc() { return exec(); }
    int run();

    virtual int message(const std::string&);

private:
    std::exception_ptr _M_e = nullptr;
};

#endif // APPLICATION_HPP

application.cpp

#include "application.hpp"
#include <QMessageBox>

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

int Application::run()
{
    try
    {
        int code = proc();
        // Check if an exception was thrown and stored in Application::notify
        // and if so, rethrow it.
        if(_M_e) std::rethrow_exception(_M_e);

        return code;
    }
    catch(std::exception& e)
    {
        return message(e.what());
    }
}

int Application::message(const std::string& message)
{
    QMessageBox::critical(0, "Error", QString::fromStdString(message));
    return 1;
}

///
/// Qt does not allow exceptions thrown from event handlers
/// to be processed outside the event loop.
/// So we catch them here, store them in _M_e
/// and tell the application to exit.
///
bool Application::notify(QObject* receiver, QEvent* event)
{
    try
    {
        return QApplication::notify(receiver, event);
    }
    catch(...)
    {
        _M_e = std::current_exception();
        exit();
    }
    return false;
}

您可以像Application一样使用QApplication课程,除了调用run函数而不是exec。 (或者,将run重命名为exec以隐藏QApplication的{​​{1}}。)

您可以覆盖exec功能以自定义错误消息。您还可以覆盖message函数,在proc之前/之后添加一些初始化/销毁代码。