好吧,上一次我以写C++为生的时候,std::auto_ptr是所有可用的std库,而boost::shared_ptr是非常流行的。我从来没有真正研究过boost提供的其他智能指针类型。我知道C++11现在提供了boost提出的一些类型,但不是全部。
那么,有没有人有一个简单的算法来确定何时使用哪个智能指针呢?优选地,包括关于哑指针(像T*这样的原始指针)和其他boost智能指针的建议。(像this这样的东西就更好了)。
发布于 2012-01-03 07:07:35
共享所有权:
所采用的shared_ptr和weak_ptr标准与他们的Boost counterparts基本相同。当您需要共享资源而又不知道哪一个将是最后一个存活的资源时,可以使用它们。使用weak_ptr观察共享资源,不会影响其生命周期,也不会中断周期。使用shared_ptr的循环不应该正常发生--两个资源不能相互拥有。
请注意,Boost还提供了shared_array,它可能是shared_ptr<std::vector<T> const>的合适替代品。
接下来,Boost提供了intrusive_ptr,这是一个轻量级的解决方案,如果您的资源已经提供了引用计数管理,并且您想要采用它来遵循RAII原则。这个没有被标准采用。
的唯一所有权:
Boost也有一个scoped_ptr,它是不可复制的,并且您不能为它指定deleter。std::unique_ptr是类固醇上的boost::scoped_ptr,当你需要一个智能指针时,它应该是你的默认选择。它允许您在其模板参数中指定删除器,并且与boost::scoped_ptr不同,它是可移动的。它在STL容器中也是完全可用的,只要您不使用需要可复制类型的操作(显然)。
再次注意,Boost有一个数组版本:scoped_array,该标准通过要求std::unique_ptr<T[]>部分专门化来统一,该部分专门化将delete[]指针而不是delete指针(使用default_deleter)。std::unique_ptr<T[]>还提供了operator[],而不是operator*和operator->。
请注意,std::auto_ptr仍在标准中,但已被弃用。§D.10 [depr.auto.ptr]
类模板
auto_ptr已弃用。注意:类模板unique_ptr(20.7.1)提供了更好的解决方案。-end笔记
没有所有权的:
当您知道资源将比引用对象/作用域存在更长的时间时,可以使用哑指针(原始指针)或引用来引用对资源的非拥有引用()。当您需要可空性或可重置性时,首选引用并使用原始指针。
如果您想要一个对资源的无所有权引用,但您不知道该资源是否会比引用它的对象存活时间更长,请将该资源打包到shared_ptr中并使用weak_ptr -您可以使用lock测试父shared_ptr是否处于活动状态,如果该资源仍然存在,它将返回一个非空的shared_ptr。如果要测试资源是否已死,请使用expired。这两个可能听起来很相似,但在并发执行方面却截然不同,因为expired只保证单个语句的返回值。一个看似无害的测试,比如
if(!wptr.expired())
something_assuming_the_resource_is_still_alive();是一种潜在的竞争条件。
发布于 2012-01-03 07:05:17
决定使用哪种智能指针是一个所有权问题。当涉及到资源管理时,如果对象A控制对象B的生存期,则它拥有对象B。例如,成员变量归其各自的对象所有,因为成员变量的生存期与对象的生存期相关。您可以根据对象的拥有方式选择智能指针。
请注意,软件系统中的所有权与所有权是分开的,就像我们在软件之外考虑的那样。例如,一个人可能“拥有”自己的房子,但这并不意味着Person对象可以控制House对象的生命周期。将这些现实世界的概念与软件概念混为一谈,肯定会让你自己陷入困境。
如果您拥有该对象的独有所有权,请使用std::unique_ptr<T>。
如果您具有对象的共享所有权...
如果所有权中没有周期,请使用std::shared_ptr<T>.
std::shared_ptr<T>,在另一个方向上使用std::weak_ptr<T>。如果对象拥有你,但有可能没有所有者,使用普通指针T* (例如父指针)。
如果对象拥有您(或者以其他方式保证存在),则使用references T&。
警告:要知道智能指针的成本。在内存或性能受限的环境中,只使用普通指针和更手动的方案来管理内存可能是有益的。
成本:
std::shared_ptr很容易地避免。它具有在复制时引用计数递增的开销,加上销毁时的递减,随后是删除持有的对象的0计数检查。根据实现的不同,这可能会使您的代码变得臃肿,并导致性能issues.示例:
struct BinaryTree
{
Tree* m_parent;
std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};二叉树并不拥有它的父级,但是树的存在意味着它的父级(或者根的nullptr )的存在,所以它使用一个普通的指针。二叉树(具有值语义)拥有其子级的唯一所有权,因此这些子级是std::unique_ptr。
struct ListNode
{
std::shared_ptr<ListNode> m_next;
std::weak_ptr<ListNode> m_prev;
};在这里,列表节点拥有它的下一个和前一个列表,所以我们定义了一个方向,并为next使用shared_ptr,为prev使用weak_ptr来打破这个循环。
发布于 2012-01-03 07:01:38
始终使用unique_ptr<T>,除非您需要引用计数,在这种情况下使用shared_ptr<T> (对于非常罕见的情况,使用weak_ptr<T>来防止引用循环)。在几乎每种情况下,可转让的唯一所有权都很好。
原始指针:只有当你需要协变返回时才有用,非拥有指针可能会发生。否则,它们就没有多大用处了。
数组指针:unique_ptr有一个针对T[]的专门化,它会对结果自动调用delete[],因此您可以安全地执行unique_ptr<int[]> p(new int[42]);等操作。shared_ptr你仍然需要一个定制的deleter,但是你不需要一个专门的共享或唯一数组指针。当然,不管怎样,这样的东西通常最好用std::vector来代替。不幸的是,shared_ptr没有提供数组访问函数,所以您仍然需要手动调用get(),但是unique_ptr<T[]>提供了operator[],而不是operator*和operator->。在任何情况下,您都必须自己进行边界检查。这使得shared_ptr对用户不那么友好,尽管可以说unique_ptr和shared_ptr的通用优势和没有Boost依赖性使它们再次成为赢家。
作用域指针:与auto_ptr一样,unique_ptr使其无关紧要。
真的没什么好说的了。在没有移动语义的C++03中,这种情况非常复杂,但在C++11中,建议非常简单。
还有其他智能指针的用法,比如intrusive_ptr或interprocess_ptr。然而,它们是非常小众的,在一般情况下完全没有必要。
https://stackoverflow.com/questions/8706192
复制相似问题