【发布时间】:2017-05-06 20:38:37
【问题描述】:
序言
在 C++11 中有 std::shared_ptr + std::weak_ptr 组合。尽管非常有用,但它有一个讨厌的问题:你cannot easily construct shared_ptr from a raw pointer。由于这个缺陷,这种智能指针通常变得“病毒式”:人们开始完全避免原始指针和引用,并在整个代码中专门使用 shared_ptr 和 weak_ptr 智能指针。因为无法将原始引用传递给需要智能指针的函数。
另一方面,有boost::intrusive_ptr。它等价于std::shared_ptr,并且可以很容易地从原始指针构造,因为引用计数器包含在对象中。不幸的是,它没有weak_ptr 伴侣,因此无法拥有可以检查无效的非拥有引用。事实上,有些人认为weak companion for intrusive_ptr is impossible。
现在,std::enable_shared_from_this,embeds a weak_ptr 直接进入你的类,这样你就可以从指向对象的指针构造 shared_ptr。但是有一个小限制(至少必须存在一个 shared_ptr),并且仍然不允许使用明显的语法:std::shared_ptr(pObject)。
另外,还有一个std::make_shared,即allocates reference counters and the user's object in a single memory chunk。这与 intrusive_ptr 的概念非常接近,但是用户的对象可以独立于引用计数块被销毁。此外,这个概念有一个不可避免的缺点:只有当所有的weak_ptr-s都消失时,整个内存块(可能很大)才会被释放。
问题
主要问题是:如何创建一对shared_ptr/weak_ptr,这将兼具std::shared_ptr/std::weak_ptr和boost::intrusive_ptr的好处?
特别是:
- shared_ptr 对对象的共享所有权建模,即对象在指向它的最后一个 shared_ptr 被销毁时被销毁。
- weak_ptr 不对对象的所有权建模,它可用于解决循环依赖问题。
- 可以检查weak_ptr是否有效:当存在指向对象的shared_ptr时有效。
- shared_ptr 可以从有效的weak_ptr 构造。
- weak_ptr 可以从指向对象的有效原始指针构造。如果存在至少一个仍然指向该对象的弱指针,则原始指针是有效的。从无效指针构造weak_ptr 会导致未定义的行为。
- 整个智能指针系统应该像上面提到的现有系统一样易于转换。
侵入性是可以的,即要求用户从给定的基类继承一次。当对象已经被销毁时持有对象的内存也是可以的。线程安全非常好(除非效率太低),但没有它的解决方案也很有趣。可以为每个对象分配多个内存块,但最好为每个对象分配一个内存块。
【问题讨论】:
-
en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr 显示了许多基于原始指针的构造函数,链接只是指向一个陷阱,即从一个原始指针中生成更多的 shared_ptr 将有许多不同的 shared_ptr 实例,所有人都想删除对象时需要。您必须制作一个 shared_ptr 然后复制它。这可能会令人讨厌,但不会使这个概念无法使用。
-
@stefaanv:毫无疑问,
std::shared_ptr+std::weak_ptr非常好用,我自己也成功使用过。但是,这个问题旨在呼吁更好的设计,它没有有这种“麻烦”。 -
侵入式指针目标和从 enable_shared_from_this 派生的类之间的病毒式传播有何不同?它们都需要了解其生命周期管理机制。
-
@stgatilov:我理解,但我想澄清一下,没有链接阅读问题似乎无法完成或导致更大的问题。确实,最好不要在这个问题中运行。但是,在工作 shared_ptr 时,应该在生命周期管理完成时完成,所以在使用原始指针时立即而不是在某个时间点完成。当需要传递给函数(而不是存储或传递给线程)时,可以从共享指针中检索原始指针。
-
如果你遵循gotw-91-solution-smart-pointer-parameters/的指导方针,智能指针的病毒性是有限的。
标签: c++ c++11 boost shared-ptr smart-pointers