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

Mar*_*tin 12 c++ qt smart-pointers

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

sti*_*472 18

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

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

当我使用类似Qt之类的东西时,我通常尝试让我的代码合理地异常安全的是使用现在已弃用的auto_ptr(unique_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
Run Code Online (Sandbox Code Playgroud)

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

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

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