关于Qt中的信号和插槽,delete和deleteLater如何工作?

有一个QNetworkReply类的对象。有一个插槽(在其他对象中)连接至其finish()信号。信号是同步的(默认信号)。只有一个线程。


在某个时刻,我想摆脱两个对象。没有更多信号或来自它们的任何东西。我希望他们走了。好吧,我想,我会用


delete obj1; delete obj2;

但是我真的可以吗?〜QObject的规范说:


在等待事件发送时删除QObject可能导致崩溃。


什么是“待处理事件”?这是否意味着在我打电话给我时delete,已经有一些“待处理事件”要传递,并且它们可能会导致崩溃,而我真的无法检查是否有任何事件?


假设我打电话给:


obj1->deleteLater(); obj2->deleteLater();

为了安全。


但是,我真的很安全吗?该deleteLater补充说,将在主回路控制时到达那里进行处理的事件。是否可以存在obj1或obj2已经存在一些未决事件(信号),在处理deleteLater 之前在主循环中等待处理?那将是非常不幸的。我不想编写代码来检查“某种程度上已删除”状态,而忽略所有插槽中的传入信号。


素胚勾勒不出你
浏览 1652回答 3
3回答

翻阅古今

如果遵循以下两个基本规则,则删除QObject通常是安全的(即,在正常实践中;可能是我不了解atm的病理情况):切勿删除插槽(或方法)中的对象,该插槽或方法被(同步,连接类型“直接”)信号直接或间接从要删除的对象中调用。例如,如果您有一个带有信号Operation :: finished()和插槽Manager :: operationFinished()的类Operation,则不想删除在该插槽中发出信号的操作对象。发出finished()信号的方法可能会在发出之后继续访问“ this”(例如访问成员),然后对无效的“ this”指针进行操作。同样,切勿删除从对象的事件处理程序中同步调用的代码中的对象。例如,请勿在其SomeWidget :: fooEvent()或从此处调用的方法/插槽中删除SomeWidget。事件系统将继续对已删除的对象->崩溃进行操作。由于回溯通常看起来很奇怪(就像访问POD成员变量时崩溃一样),尤其是当您具有复杂的信号/插槽链(其中删除可能会发生几步下降,最初是由信号或事件发起的)时,两者都很难追踪。被删除的对象。这种情况是deleteLater()的最常见用例。它确保当前事件可以在控件返回到事件循环之前完成,事件循环然后删除该对象。我发现,另一个更好的方法通常是使用排队的连接/ QMetaObject :: invokeMethod(...,Qt :: QueuedConnection)延迟整个操作。

吃鸡游戏

您推荐的文档的后两行给出了答案。从〜QObject,在等待事件发送时删除QObject可能导致崩溃。如果QObject与当前正在执行的线程不在同一线程中,则不能直接删除它。使用deleteLater()代替,这将导致事件循环在所有未决事件传递到对象后删除该对象。它明确表示我们不要从其他线程中删除。由于您只有一个线程应用程序,因此删除是安全的QObject。否则,如果您必须在多线程环境deleteLater()中将其删除,请使用它将QObject在处理完所有事件后将其删除。

慕桂英546537

您可以阅读有关以下内容之一的Delta对象规则来找到问题的答案:信号安全(SS)。从一个对象的信号之一调用的插槽中调用对象(包括析构函数)上的方法必须是安全的。分段:QObject的核心是支持在发信号时删除。为了利用它,您只需确保您的对象在删除后不尝试访问其自己的成员。但是,大多数Qt对象不是以这种方式编写的,也不要求它们两者都存在。因此,如果需要在对象的信号之一期间删除对象,建议始终调用deleteLater(),因为“删除”可能会使应用程序崩溃。不幸的是,何时使用“ delete”和deleteLater()并不总是很清楚。也就是说,代码路径具有信号源并不总是很明显。通常,您可能会有一段代码在今天安全的某些对象上使用“删除”,但是在将来的某个时候,同一代码块最终会从信号源中被调用,现在您的应用程序突然崩溃了。解决此问题的唯一通用方法是始终使用deleteLater(),即使乍一看似乎没有必要。通常,我认为Delta对象规则是每个Qt开发人员必须阅读的内容。这是极好的阅读材料。
打开App,查看更多内容
随时随地看视频慕课网APP