如果智能指针所持有的对象在其他地方被删除会发生什么?

时间:2012-03-02 23:13:10

标签: c++ qt smart-pointers

这个问题总是让我很烦恼,特别是当我用Qt编程的时候。 由于Qt使用对象所有权树,因此传递指针,例如通过myBoostSharedPtr.get()可以隐式转让所有权。 现在考虑一些Qt对象被破坏并且整个对象树被破坏但智能指针仍处于活动状态的情况,例如作为另一个班级的成员。 如果之后智能指针被删除会发生什么? 双重删除所有令人讨厌的后果? 一些智能指针实现会阻止这种情况吗?

3 个答案:

答案 0 :(得分:18)

我很想对Qt的内存模型的弱点咆哮,其中很多API仍然接受原始指针,期望客户端分配它,而接受指针的QObject删除它。

您的问题的答案是未定义的行为shared_ptr没有机制来检测指针是否被shared_ptr本身以外的东西删除,因此它通常会尝试第二次释放指针(在悬空指针上调用delete)。如果你想使用shared_ptr,你必须坚持使用shared_ptr作为唯​​一的内存管理器。即使对于Qt自己的QSharedPointer也是如此。

在使用类似Qt之类的东西时,我通常尝试让我的代码合理地异常安全,但是使用现已弃用auto_ptrunique_ptr替换它,如果你有C +则更安全+11可用)。这是我之前唯一想要使用auto_ptr的地方,因为它提供了release方法。

unique_ptr<QListWidget> widget(new QListWidget(...));
// do stuff with the widget to set it up for your GUI
some_layout.addWidget(widget.release()); // <-- release ownership so that 
                                         // the layout now becomes responsible 
                                         // for memory management
// ^^ auto_ptr works above if we don't have C++11

如果在Qt已经对内存进行内存管理之后需要保持对象的持久性指针(例如:在将其插入布局后指向窗口小部件的指针),只需使用常规指针即可。由于Qt现在是该对象的内存管理器,所以你可以做得更好。

但是,您可以通过QObject::destroyed信号检测对象何时被销毁(因此当指针无效时)。

如果你想变得非常复杂,你可以构建一个只存储QObject子类的共享指针类型。由于QObject提供了一个被破坏的信号,这种自定义智能指针可以检测QObject何时被销毁信号销毁,并避免再次尝试删除该对象。但是,它可能会在多线程代码中依赖于这个信号,如果你实现了一个共享指针,它可能成为处理原子引用计数的一个负担,在构造指针的站点捕获一个删除函数(以避免模块)边界新/删除不匹配)等。

答案 1 :(得分:1)

是的,很有可能,不,他们没有,我看不出他们怎么可能。你必须依赖合同,你传递指针的东西不会取得所有权(除非文档声明它),如果是后者,不要将它包装在你身边的智能指针中。

答案 2 :(得分:1)

您不能在父QObject和智能指针之间拥有共享所有权,并阻止其他人删除另一个,但您可以仅使用QObject跟踪删除任何QWeakPointer(或QPointer)。

请参阅http://qt-project.org/doc/qt-4.8/qweakpointer.html#tracking-qobject

更新:在Qt 5中,不推荐使用QObjectQSharedPointer管理QWeakPointer的{​​{1}},而忽略QPointer(这是{1}}本身undeprecated)。