17

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:

  1. Sender code, what if it deletes before myObject is used? Dangling Pointer

  2. 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?

4

4 回答 4

10

您可以根据需要将信号与任意数量的插槽连接,因此您应该确保这些插槽中没有一个能够执行您不希望它们对您的对象执行的操作:

  • 如果您决定将指针作为参数传递,那么您将在您描述的问题中运行,内存管理 - 这里没有人可以为您工作,因为您必须建立一个处理分配/删除的策略。有关如何解决此问题的一些想法,请参阅COM世界中的内存管理规则。
  • 如果您决定将参数作为引用传递,那么您不必担心内存管理,而只需担心插槽以意想不到的方式修改您的对象。除非必须,否则不要传递指针,而是尽可能使用引用。
  • 如果您决定传递const引用,则根据您的连接类型,QT 将为您传递对象的值(有关详细信息,请参阅this
  • 避免任何问题并按价值传递:)

有关在信号中传递指针的一些想法,另请参阅此问题

于 2010-07-06T06:44:56.033 回答
5

对于您的第一个问题,请使用QPointer

对于你的第二个问题,

如果我清楚地理解,即使您正在发送myObject,您仍然 myObject在发出信号的类中有参考。那么它会是内存泄漏还是悬空指针呢?您仍然可以从发出的类访问,myObject不是吗?

希望清楚..

编辑 :

根据您的评论,我相信您正在释放/删除插槽中的对象。现在我假设您的问题是,如果(内存释放)插槽被调用一次、两次或根本不调用怎么办。

您可以为此使用 QPointer。从 Qt 文档中,

受保护的指针 ( QPointer) 在您需要存储指向QObject其他人拥有的 a 的指针时很有用,因此在您仍然持有对它的引用时可能会被销毁。您可以安全地测试指针的有效性。

Qt 文档本身的一个例子,

     QPointer<QLabel> label = new QLabel;
     label->setText("&Status:");
     ...
     if (label)
         label->show();

解释是这样的。。

如果同时删除 QLabel,label 变量将保存 0 而不是无效地址,并且永远不会执行最后一行。这里 QLabel 将是你的MyClass,标签是你的myObject。在使用它之前检查Nullity

于 2010-07-06T06:43:16.930 回答
3

在 1): 发件人应该小心。当同步发送信号(而不是排队)时,当接收器接收到它时,对象仍然是活动的。如果接收者需要存储它,那么只有 QPointer 会有所帮助,但是 MyClass 需要从 QObject 派生,从上下文中看起来是错误的。无论如何,这是一个普遍的生命周期问题,不是非常特定于信号/插槽。

替代方案:使用值类并通过 const 引用发送它。如果 MyClass 可以有子类,则传递一个 const QSharedPointer&

关于 deleteLater: deleteLater() 在这里没有帮助。这将使排队连接更安全,而对于直接连接则没有区别。deleteLater() 发挥作用的一种用途是接收方是否需要删除发送方。然后应该总是使用 deleteLater(),这样发送者就可以完成他正在做的事情,否则会崩溃。

于 2010-07-06T07:03:50.713 回答
0

总之一句话(好吧,函数名) - deleteLater() :) 所有 QObjects 都有它。它会将对象标记为删除,然后在下一次事件循环更新时发生。

于 2010-07-06T06:06:54.367 回答