我可以从Qt中的异常处理程序中发出信号吗
Can I emit a signal from within a exception handler in Qt?
Qt文档说明:
从Qt的信号槽连接机制调用的槽抛出异常被认为是未定义的行为,除非它在槽中处理
我希望在其中一个UI对象中设置错误文本。实现这一点的一种优雅方式是信号/插槽机制。由于I可以在插槽中有异常(如果我也在插槽中处理它们),问题仍然存在:
从异常处理程序内部发出信号是否安全
一个相关的问题是连接机制:
使用排队连接更好(或更糟),还是直接连接可以
我想做这样的事情:
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文档和此处都有介绍。
允许在catch块内部发出信号。仔细考虑您用于信号的参数,记住客户端代码可以选择是直接连接到该信号还是通过排队连接(即,您不知道在发出信号时会使用哪个)。在您的示例中,您的信号有一个const char*
参数,在catch块中,您使用异常的what()
函数作为该参数。如果客户端代码通过排队连接连接到信号,则在调用插槽时,const char*
自变量可能不再存在。如果要从catch块发出信号,请考虑仅使用可安全复制的参数类型(例如,通过值传递的std::string
而不是const char*
)。
如果您想在非GUI线程中捕获异常并在那里发出信号,然后在GUI线程中捕捉该信号以向用户显示某种错误消息,则需要排队连接(仅为一个示例使用场景)。只要您注意如上所述使用的参数类型,排队连接是可以的。就我个人而言,我认为明智的做法是假设捕获块发出的信号可以通过排队连接连接(对未来的更改更健壮,等等)。
更新:
具体来说,使用排队连接而不是直接连接是好是坏,这取决于对你来说重要的是什么。直接连接是最有效的,可以保证您的代码立即响应异常,但您要负责线程安全。直接连接实际上只是将信号发射变成一个普通的函数调用,尽管在这个过程中需要一些内务处理。排队连接将把对异常的响应延迟到未来的任意点,即使它在同一线程中响应(如果拥有插槽的对象属于同一线程,但可能会先处理其他信号,则当控制返回到当前线程的事件循环时,将处理排队响应)。
您的问题没有提到其他连接类型,但默认为Qt::AutoConnection
,这意味着如果拥有插槽的对象属于同一线程,则行为将与直接相同,如果属于不同线程,则排队类似,因此这种连接类型可能会导致您的代码立即响应异常,或者可能会延迟,这意味着您再次需要自己处理线程安全问题。Qt::BlockingQueuedConnection
可以保证您的代码立即响应,但对性能有潜在的负面影响,并且需要更加小心地避免死锁等。
因此,虽然您更新的问题表明您没有专门询问线程,但线程注意事项与您的问题密切相关,即哪种连接类型更好。最终,这取决于您对更好的标准。
它是安全的。从异常处理程序运行代码和从其他地方运行代码没有区别。直接连接和排队连接都一样好。
- Qt VTK交互风格的信号到小部件
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- 如何在qt中将信号和插槽与另一个对象连接 --解决了
- Qt将信号与另一个类方法连接
- 通过插槽和信号在不同线程中的两个qt对象之间进行通信
- 控制带有信号/插槽的Qt QML滑动视图
- Qt 信号/插槽问题
- Qt信号和插槽如果从QRunnable或其他线程调用,则不起作用
- Qt:如何通知对象已建立涉及它的信号槽连接
- Qt/C++ 系统单元启动/停止时的信号
- C++Qt信号和插槽
- Qt moveToThread,带有参数的信号/插槽
- 如何在Qt测试框架中对信号进行基准测试?
- Qt - Q_PROPERTY的通知信号未发出有关成员更改的通知信号
- 当再次触发信号时,从Qt插槽执行的功能被第二次调用时会发生什么?
- 使用std::move将std::unique_ptr作为qt信号参数传递
- 使用std::bind将Qt信号连接到插槽
- Qt:向死/停止线程发送信号
- 呼叫函数直接与发射信号(QT-信号和插槽)
- 没有这样的插槽/信号(Qt)