sbi*_*sbi 224 c++ pointers smart-pointers c++-faq c++11
好吧,所以我最后一次以C++为生,std::auto_ptr
所有的std lib都可用,而且boost::shared_ptr
风靡一时.我从未真正研究过提供的其他智能指针类型.我知道C++ 11现在提供了一些类型的提升,但不是全部.
那么有人有一个简单的算法来确定何时使用哪个智能指针?优选地包括关于哑指针(诸如原始指针T*
)和其他增强智能指针的建议.(像这样的东西会很棒).
Xeo*_*Xeo 178
共享所有权:
采用的shared_ptr
和weak_ptr
标准与Boost对应的几乎相同.当您需要共享资源并且不知道哪个资源将是最后一个存活时使用它们.使用weak_ptr
观察共享资源而不影响其寿命,不打破循环.shared_ptr
通常不应该发生循环- 两个资源不能互相拥有.
请注意,Boost另外提供shared_array
,可能是一个合适的替代品shared_ptr<std::vector<T> const>
.
接下来,Boost提供intrusive_ptr
了一个轻量级的解决方案,如果您的资源已经提供了参考计数管理,并且您希望将其用于RAII原则.标准没有采用这个.
独特的所有权:
Boost还有一个scoped_ptr
不可复制的,您无法指定删除者.std::unique_ptr
是boost::scoped_ptr
类固醇,当你需要一个智能指针时应该是你的默认选择.它允许您在其模板参数中指定删除器,并且可以移动,不像boost::scoped_ptr
.只要您不使用需要可复制类型的操作(显然),它也可以在STL容器中完全使用.
再次注意,Boost有一个数组版本:scoped_array
,标准统一通过要求std::unique_ptr<T[]>
部分特化delete[]
而不是指针delete
(用default_delete
r).std::unique_ptr<T[]>
也提供operator[]
而不是operator*
和operator->
.
请注意,std::auto_ptr
它仍然在标准中,但已弃用.
§D.10 [depr.auto.ptr]
auto_ptr
不推荐使用类模板.[ 注意:类模板unique_ptr
(20.7.1)提供了更好的解决方案.- 尾注 ]
无所有权:
使用哑指针(原始指针)或对资源的非拥有引用的引用,以及当您知道资源将比引用对象/范围更长时.当您需要可空性或可重置性时,首选引用并使用原始指针.
如果您想要对资源进行非拥有引用,但是您不知道该资源是否会比引用它的对象更长,请将资源打包shared_ptr
并使用weak_ptr
- 您可以测试父项是否处于shared_ptr
活动状态lock
,这将是shared_ptr
如果资源仍然存在,则返回非null值.如果要测试资源是否已死,请使用expired
.这两者可能听起来很相似,但在并发执行方面却非常不同,因为expired
只保证它对该单个语句的返回值.一个看似无辜的测试
if(!wptr.expired())
something_assuming_the_resource_is_still_alive();
Run Code Online (Sandbox Code Playgroud)
是一种潜在的竞争条件.
Pet*_*der 127
决定使用什么智能指针是一个所有权问题.对于资源管理,如果对象A 控制对象B的生命周期,则对象A 拥有对象B.例如,成员变量由其各自的对象拥有,因为成员变量的生命周期与对象的生命周期相关联.您可以根据对象的拥有方式选择智能指针.
请注意,软件系统中的所有权与所有权是分开的,正如我们在软件之外所想到的那样.例如,一个人可能"拥有"他们的家,但这并不一定意味着一个Person
对象可以控制一个对象的生命周期House
.将这些真实世界的概念与软件概念相结合是将自己编入漏洞的可靠方法.
如果您拥有该对象的唯一所有权,请使用std::unique_ptr<T>
.
如果您拥有该对象的所有权...
- 如果所有权中没有周期,请使用std::shared_ptr<T>
.
- 如果存在循环,则定义"方向"并std::shared_ptr<T>
在一个方向和另一个方向上使用std::weak_ptr<T>
.
如果对象拥有你,但有可能没有所有者,请使用普通指针T*
(例如父指针).
如果对象拥有您(或以其他方式保证存在),请使用引用T&
.
警告:注意智能指针的成本.在内存或性能受限的环境中,仅使用具有更多手动方案的普通指针来管理内存可能是有益的.
费用:
std::shared_ptr
具有复制时引用计数增量的开销,加上销毁时的减量,然后是删除保持对象的0计数检查.根据实现情况,这会使代码膨胀并导致性能问题.例子:
struct BinaryTree
{
Tree* m_parent;
std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};
Run Code Online (Sandbox Code Playgroud)
二叉树不拥有其父级,但树的存在意味着其父级(或nullptr
根)的存在,因此使用普通指针.二叉树(具有值语义)拥有其子项的唯一所有权,因此它们是std::unique_ptr
.
struct ListNode
{
std::shared_ptr<ListNode> m_next;
std::weak_ptr<ListNode> m_prev;
};
Run Code Online (Sandbox Code Playgroud)
这里,列表节点拥有其下一个和前一个列表,因此我们定义一个方向并shared_ptr
用于next和weak_ptr
prev来打破循环.
Pup*_*ppy 19
unique_ptr<T>
除非需要引用计数,否则一直使用,在这种情况下使用shared_ptr<T>
(对于极少数情况,weak_ptr<T>
要防止参考循环).几乎在所有情况下,可转让的独特所有权都很好.
原始指针:只有当你需要协变回报,非拥有指向可能发生时才有用.否则它们并不十分有用.
数组指针:unique_ptr
具有T[]
自动调用delete[]
结果的特化,因此您可以安全地执行此操作unique_ptr<int[]> p(new int[42]);
.shared_ptr
你仍然需要一个自定义删除器,但你不需要专门的共享或唯一的数组指针.当然,这些东西通常最好被取而代之std::vector
.遗憾的是,shared_ptr
它不提供数组访问功能,因此您仍然需要手动调用get()
,而是unique_ptr<T[]>
提供operator[]
而不是operator*
和operator->
.无论如何,你必须自己检查.这使得shared_ptr
用户友好性稍差,虽然可以说是通用优势而且没有Boost依赖性,unique_ptr
而且shared_ptr
再次获胜者.
Scoped指针:无关紧要unique_ptr
,就像auto_ptr
.
真的没什么了不起的.在没有移动语义的C++ 03中,这种情况非常复杂,但在C++ 11中,建议非常简单.
还有其他智能指针的用途,比如intrusive_ptr
或interprocess_ptr
.然而,在一般情况下,它们非常适合并且完全没有必要.
何时使用的案例unique_ptr
:
何时使用的案例shared_ptr
:
何时使用的案例weak_ptr
:
随意编辑和添加更多
归档时间: |
|
查看次数: |
32486 次 |
最近记录: |