【问题标题】:Can I emit a signal from within a exception handler in Qt?我可以从 Qt 的异常处理程序中发出信号吗?
【发布时间】:2015-11-12 21:14:58
【问题描述】:

Qt Documentation 声明:

从 Qt 的信号槽连接机制调用的槽中抛出异常被认为是未定义的行为,除非它在槽内处理

我希望在其中一个 UI 对象中设置错误文本。一个优雅的方法是信号/槽机制。由于我可以在插槽中有异常(如果我也在插槽中处理它们),问题仍然存在:

从异常处理程序中发出信号是否安全?

一个相关的问题是连接机制:

使用排队连接更好(或更差),还是直接连接可以?

我想做这样的事情:

class myclass : public QObject
{
    Q_OBJECT
public:
    myclass() {}

signals:
    void error_message(const std::string &);

public slots:
    void do_mogrify()
    {
         try {
              // complex function that may throw
         } catch (std::exception & e) {
             emit error_message(std::string(e.what()));
         }
    }
} 

更新:

Craig Scott 在他的回答中指出,在执行 slot 函数时,提供给信号的参数可能不再存在。因此,我已将示例更改为使用 std::string,如果需要(排队连接)将被复制。我想它也适用于引用。

我想强调一下,这个问题不是关于线程的。从线程发出信号在Qt Documentationherehere 中进行了介绍。

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    允许在 catch 块内发出信号。仔细考虑您用于信号的参数,请记住客户端代码可以选择是直接连接到该信号还是通过排队连接(即您不知道在发出信号时将使用哪个)。在您的示例中,您的信号有一个 const char* 参数,并且在 catch 块中,您使用异常的 what() 函数作为该参数。如果客户端代码通过队列连接连接到信号,则const char* 参数可能不再存在于调用槽的位置。如果您想从 catch 块发出信号,请考虑仅使用可安全复制的参数类型(例如,std::string 按值传递而不是 const char*)。

    如果您想在非 GUI 线程中捕获异常并在那里发出信号,则需要排队连接,然后在 GUI 线程中捕获该信号以向用户显示某种错误消息(仅一个示例使用场景)。只要您小心使用上述参数类型,排队连接就可以了。就个人而言,我认为假设从您的 catch 块发出的信号可以通过排队连接连接是明智的(对未来的变化等更健壮)。

    更新:

    具体回答使用排队连接而不是直接连接是更好还是更差的问题,这取决于对您而言重要的是什么。直接连接是最有效的,并且可以保证您的代码立即响应异常,但您要对线程安全负责。直接连接实际上只是将信号发射转换为普通的函数调用,尽管在此过程中需要进行一些处理。排队的连接会将异常的响应延迟到将来的任意点,即使它在同一个线程中响应(如果拥有该插槽的对象属于,则当控制返回到当前线程的事件循环时,将处理排队的响应同一个线程,但可能会先处理其他信号)。

    您的问题没有提及其他连接类型,但默认为Qt::AutoConnection,这意味着如果拥有该插槽的对象属于同一线程或 ,则行为将与 direct 相同>queued 如果它属于不同的线程,那么这种连接类型可能会导致您的代码立即响应异常或者它可能会延迟,这意味着您再次需要自己处理线程安全。 Qt::BlockingQueuedConnection 可以保证您的代码立即响应,但对性能有潜在的负面影响,并且需要更加小心以避免死锁等。

    因此,虽然您更新后的问题表明您没有专门询问线程,但线程注意事项与您关于哪种连接类型更好的问题密切相关。最终,这取决于您对更好的标准。

    【讨论】:

    • 感谢您的详细回答。我对“更好”没有明确的标准。与此同时,我已经实现了上述异常处理(使用“QString”作为参数。它还有一些其他有趣的结果(我将发布更新)
    【解决方案2】:

    这是安全的。从异常处理程序和从其他地方运行代码之间没有区别。直接连接和排队连接都一样好。

    【讨论】:

    • 我曾经在异常处理程序中使用信号/槽在另一个线程(工作线程->主/GUI线程)中进行错误处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-05
    • 2013-05-27
    • 2011-05-25
    • 2011-09-25
    • 1970-01-01
    相关资源
    最近更新 更多