信号发送的对象的删除,信号中对象的所有权,Qt
在这里,我的信号声明:
signals:
void mySignal(MyClass *);
以及我如何使用它:
MyClass *myObject=new myClass();
emit mySignal(myObject);
我的问题来了: 谁负责删除 myObject:
发送者代码,如果它在使用 myObject 之前删除怎么办?悬空指针
与信号连接的插槽,如果没有插槽或多个插槽与信号连接怎么办?内存泄漏或悬空指针
Qt 如何在其内置信号中管理这种情况?它使用内部引用计数吗?
您的最佳实践是什么?
Here, my signal declaration:
signals:
void mySignal(MyClass *);
And how I'm using it:
MyClass *myObject=new myClass();
emit mySignal(myObject);
Here comes my problem: Who is responsible for deletion of myObject:
Sender code, what if it deletes before myObject is used? Dangling Pointer
The slot connected to signal, what if there is no slot or more than one slot which is connected to the signal? Memory Leak or Dangling Pointer
How does Qt manage this situation in its build-in signals? Does it use internal reference counting?
What are your best practices?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以将信号与任意数量的插槽连接,因此您应该确保这些插槽中没有一个能够执行您不希望它们对对象执行的操作:
const
引用,那么根据您的连接类型,QT 将为您传递对象的值(请参阅 此了解一些详细信息)另请参阅此 问题,了解有关在信号中传递指针的一些想法。
You can connect a signal with as many slots as you want so you should make sure that none of those slots are able to do something you would not want them to do with your object:
const
reference then, depending on your connection type, QT will pass the value of the object for you (see this for some details)See also this question for some thoughts about passing pointers in signals.
对于你的第一个问题,请使用 QPointer
对于你的第二个问题,
如果我理解清楚的话,即使您发送
myObject
,您在发出信号的类中仍然拥有引用myObject
。那怎么会是内存泄漏或者悬空指针呢?您仍然可以从发出的类中访问myObject
,不是吗?希望很清楚..
编辑:
根据您的评论,我相信您正在释放/删除插槽中的对象。现在我假设你的问题是,如果(内存释放)插槽被调用一次、两次或根本不被调用怎么办?
您可以使用 QPointer 来实现这一点。从 Qt 文档来看,
每当您需要存储指向由其他人拥有的
QObject
的指针时,受保护的指针 (QPointer
) 就很有用,因此可能会当你仍然持有对它的引用时就被销毁了。您可以安全地测试指针的有效性。Qt 文档本身的一个示例,
解释如下。
如果同时删除 QLabel,标签变量将保留 0 而不是地址无效,最后一行永远不会被执行。这里 QLabel 将是您的
MyClass
,而 label 是您的myObject
。在使用它之前检查是否无效。For your first question, use QPointer
For your second question,
If I understood clearly, even if you are sending
myObject
, you still have the referencemyObject
in the class where you are emitting the signal. Then how will it be a memory leak or a dangling pointer? You can still access themyObject
from the emitted class, isn't?Hope am clear..
Edit :
From your comments I believe you are releasing/deleting the objects in the slots. Now I assume your problem is, what if the (memory releasing) slot gets called once,twice or not called at all.
You can use QPointer for that. From the Qt documentation,
Guarded pointers (
QPointer
) are useful whenever you need to store a pointer to aQObject
that is owned by someone else, and therefore might be destroyed while you still hold a reference to it. You can safely test the pointer for validity.An example from the Qt documentation itself,
the explanation goes on like this..
If the QLabel is deleted in the meantime, the label variable will hold 0 instead of an invalid address, and the last line will never be executed. Here QLabel will be your
MyClass
and label is yourmyObject
. And before using it check for Nullity.1):发件人应小心。当同步发送信号(而不是排队)时,当接收者接收到该对象时,该对象仍然处于活动状态。如果接收者需要存储它,只有 QPointer 会有所帮助,但是 MyClass 需要从 QObject 派生,从上下文来看这是错误的。
无论如何,这是一个普遍的生命周期问题,不是特定于信号/时隙的。
替代方案:使用值类并通过 const 引用发送它。如果 MyClass 可以有子类,则传递一个 const QSharedPointer&
关于deleteLater:deleteLater() 在这里没有帮助。它将使排队连接更加安全,对于直接连接来说没有什么区别。 deleteLater() 发挥作用的一个用途是接收方需要删除发送方。那么应该总是使用deleteLater(),这样发送者就可以完成他正在做的事情,否则就会崩溃。
At 1): The sender should take care. When sending the signal synchronously (instead of queued), the object is still alive when a receiver receives it. If the receiver needs to store it, only a QPointer would help, but then MyClass needs to derive from QObject, which looks wrong from the context.
Anyway, that is a general lifetime issue, not very signal/slot-specific.
Alternatives: Use a value class and send it via const reference. If MyClass can have subclasses, pass a const QSharedPointer&
About deleteLater: deleteLater() doesn't help here. It would make queued connections any safer, and for direct connections it makes no difference. The one use where deleteLater() comes into play is if the receiver needs to delete the sender. Then one should always use deleteLater(), so the sender can complete what he was doing, which would otherwise crash.
一句话(好吧,函数名)——deleteLater() :) 所有 QObject 都有它。它将标记要删除的对象,然后这将在下一次事件循环更新时发生。
In a word (alright, function name) - deleteLater() :) All QObjects have it. It will mark the object for deletion, and this will then happen on the next event loop update.