QObject 作为另一个 QObject 的字段?
Posted
技术标签:
【中文标题】QObject 作为另一个 QObject 的字段?【英文标题】:QObject as a field of another QObject? 【发布时间】:2015-10-22 08:50:12 【问题描述】:我们通常编写拥有其他 QObject 的 QObject 派生类,如下所示:
class Foo: public QObject
Q_OBJECT
public:
Foo(QObject *parent = nullptr)
: QObject(parent), bar(nullptr)
bar = new Bar(this);
private:
Bar *bar;
;
但是,在查看同事的代码时,我发现了这种模式:
class Foo: public QObject
Q_OBJECT
public:
Foo(QObject *parent = nullptr)
: QObject(parent)
private:
Bar bar;
;
它似乎按预期工作,但这样做实际上是否安全,除非有明显的“不要bar->deleteLater()
”?
【问题讨论】:
【参考方案1】:是的,这样做是安全的,只要您不尝试删除 bar,因为它会在删除 Foo 时自动释放。
可以说,走哪条路的决定取决于 Foo
和 Bar
的实际情况。
当Bar
是一个类的组合时,我更倾向于使用第二种方法。在这种情况下,它是它的一部分,这意味着没有 Bar,Foo 没有意义。
相比之下,如果 Bar 是一个聚合类,则指向其对象的指针更实用。在这种情况下,Bar 为 Null,Foo 仍然存在。
例如,Foo 是 Car,Bar 是司机。一辆车可能有也可能没有司机,但它仍然是一辆车,所以车上的指针会更有意义。此外,这允许通过简单地更改指向它的指针来更改汽车中的驾驶员。
【讨论】:
说,Foo
实现了一些需要咨询网络的功能,而Bar
就是QTcpSocket
。是聚合还是关联?
如果对象 Foo 在没有 Bar 的情况下仍然可以被分类并作为对象起作用,那么它就是聚合。如果 Foo 需要 Bar 作为对象才有意义,那么它就是组合。不要太担心条款。相反,请考虑对象的生命周期。如果 Bar 是 QTcpSocket,Foo 应该在没有 Bar 的情况下存在还是 Foo 可以使用不同的 Bar?如果是,则使用指针。【参考方案2】:
更好的问题是:为什么通过将bar
作为指针的额外间接来过早地悲观您的代码?第二种方法不仅安全(为什么不安全?),由于引用的局部性、堆碎片等原因,它是首选的。第二个代码片段中唯一缺少的是 bar 的父级的初始化。如果您希望将 Foo
实例移动到另一个线程,则需要这样做。如果不这样做,您将过早地任意限制Foo
的功能。
在 C++11 中:
class Bar : public QObject ... ;
class Foo: public QObject
Q_OBJECT
public:
Foo(QObject *parent = nullptr) : QObject(parent)
private:
Bar bar this ;
;
【讨论】:
这不会导致bar
的双重破坏吗?一次在~QObject()
中,又一次在编译器生成的“调用成员的析构函数”中 `~Foo()"?
@Joker_vD 不,不会。我不明白这种普遍的误解是从哪里来的。 QObject
对它的孩子没有无限的记忆。如果你摧毁了一个对象的任何孩子,它会立即忘记它们;任何其他行为都是无稽之谈。因此,一旦bar.~Bar
运行,您就清楚了。 Foo 基地~QObject
会做正确的事。【参考方案3】:
已保存且 100% 有效。然而,第二段代码只有在Bar
有一个不带参数的构造函数时才有效。
但是,如果Bar
的构造函数需要参数,您仍然需要将其创建为Foo
构造函数的初始化列表的一部分。
class Foo: public QObject
Q_OBJECT
public:
Foo(QObject *parent = nullptr)
: QObject(parent)
, bar(arg1, arg2)
private:
Bar bar;
;
【讨论】:
【参考方案4】:这应该是安全的。正如您所指出的,您当然不应该删除 bar,因为它将被 Foo 的析构函数删除。如果在 bar 上设置了父级,则应小心,以免发生双重删除。
【讨论】:
正如 Kuba Ober 所说,您的最后一句话是不正确的。在(非指针)对象成员变量上设置父级很好(它不是绝对必要的,但对于在父级上调用 MoveToThread 后保持适当的线程亲和性等事情很有帮助)。一旦被删除,QObject 析构函数就不会再尝试删除它。 @ScottG 没关系,成员变量 QObject 的父级是封闭的 QObject。这不是无条件的好。如果 parent 是别的东西,并且首先被破坏,它会崩溃和燃烧。以上是关于QObject 作为另一个 QObject 的字段?的主要内容,如果未能解决你的问题,请参考以下文章