信号发送的对象的删除,信号中对象的所有权,Qt

发布于 2024-09-07 23:57:12 字数 470 浏览 6 评论 0原文

在这里,我的信号声明:

signals:
    void mySignal(MyClass *);

以及我如何使用它:

MyClass *myObject=new myClass();
emit mySignal(myObject);

我的问题来了: 谁负责删除 myObject:

  1. 发送者代码,如果它在使用 myObject 之前删除怎么办?悬空指针

  2. 与信号连接的插槽,如果没有插槽或多个插槽与信号连接怎么办?内存泄漏或悬空指针

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:

  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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤独难免 2024-09-14 23:57:12

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

  • 如果您决定传递指针作为参数,那么您将在您描述的问题中运行,内存管理 - 这里没有人可以为您工作,因为您必须建立处理分配/删除的策略。有关如何解决此问题的一些想法,请参阅 COM世界。
  • 如果您决定传递参数作为引用,那么您不必担心内存管理,而只需担心插槽以意想不到的方式修改您的对象。除非必须,否则不要传递指针 - 如果可以的话,请使用引用。
  • 如果您决定传递 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:

  • if you decide to pass a pointer as a parameter then you will be running in the issues you describe, memory management - here nobody can to the work for you as you will have to establish a policy for dealing with allocation/deletion. To some ideas on how to address this see the Memory Management Rules in the COM world.
  • if you decide to pass a parameter as a reference then you don't have to worry about memory management but only about slots modifying your object in unexpected ways. The ideea is not to pass pointers unless you have to - instead use references if you can.
  • if you decide to pass a const reference then, depending on your connection type, QT will pass the value of the object for you (see this for some details)
  • avoid any problems and pass by value :)

See also this question for some thoughts about passing pointers in signals.

愿得七秒忆 2024-09-14 23:57:12

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

对于你的第二个问题,

如果我理解清楚的话,即使您发送 myObject,您在发出信号的类中仍然拥有引用 myObject。那怎么会是内存泄漏或者悬空指针呢?您仍然可以从发出的类中访问myObject,不是吗?

希望很清楚..

编辑:

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

您可以使用 QPointer 来实现这一点。从 Qt 文档来看,

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

Qt 文档本身的一个示例,

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

解释如下。

如果同时删除 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 reference myObject 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 the myObject 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 a QObject 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,

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

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 your myObject. And before using it check for Nullity.

情释 2024-09-14 23:57:12

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.

﹏半生如梦愿梦如真 2024-09-14 23:57:12

一句话(好吧,函数名)——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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文