首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在什么情况下我应该使用哪种指针?

在什么情况下我应该使用哪种指针?
EN

Stack Overflow用户
提问于 2012-01-03 06:58:38
回答 4查看 37.2K关注 0票数 236

好吧,上一次我以写C++为生的时候,std::auto_ptr是所有可用的std库,而boost::shared_ptr是非常流行的。我从来没有真正研究过boost提供的其他智能指针类型。我知道C++11现在提供了boost提出的一些类型,但不是全部。

那么,有没有人有一个简单的算法来确定何时使用哪个智能指针呢?优选地,包括关于哑指针(像T*这样的原始指针)和其他boost智能指针的建议。(像this这样的东西就更好了)。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-01-03 07:07:35

共享所有权:

所采用的shared_ptrweak_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只保证单个语句的返回值。一个看似无害的测试,比如

代码语言:javascript
复制
if(!wptr.expired())
  something_assuming_the_resource_is_still_alive();

是一种潜在的竞争条件。

票数 185
EN

Stack Overflow用户

发布于 2012-01-03 07:05:17

决定使用哪种智能指针是一个所有权问题。当涉及到资源管理时,如果对象A控制对象B的生存期,则它拥有对象B。例如,成员变量归其各自的对象所有,因为成员变量的生存期与对象的生存期相关。您可以根据对象的拥有方式选择智能指针。

请注意,软件系统中的所有权与所有权是分开的,就像我们在软件之外考虑的那样。例如,一个人可能“拥有”自己的房子,但这并不意味着Person对象可以控制House对象的生命周期。将这些现实世界的概念与软件概念混为一谈,肯定会让你自己陷入困境。

如果您拥有该对象的独有所有权,请使用std::unique_ptr<T>

如果您具有对象的共享所有权...

如果所有权中没有周期,请使用std::shared_ptr<T>.

  • If
  • ,定义一个“方向”,在一个方向上使用std::shared_ptr<T>,在另一个方向上使用std::weak_ptr<T>

如果对象拥有你,但有可能没有所有者,使用普通指针T* (例如父指针)。

如果对象拥有您(或者以其他方式保证存在),则使用references T&

警告:要知道智能指针的成本。在内存或性能受限的环境中,只使用普通指针和更手动的方案来管理内存可能是有益的。

成本:

  • 如果你有一个自定义的deleter (例如,你使用分配池),那么这将导致每个指针的开销,这可以通过手动deletion.
  • std::shared_ptr很容易地避免。它具有在复制时引用计数递增的开销,加上销毁时的递减,随后是删除持有的对象的0计数检查。根据实现的不同,这可能会使您的代码变得臃肿,并导致性能issues.
  • Compile时间。与所有模板一样,智能指针对编译时间有负面影响。

示例:

代码语言:javascript
复制
struct BinaryTree
{
    Tree* m_parent;
    std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};

二叉树并不拥有它的父级,但是树的存在意味着它的父级(或者根的nullptr )的存在,所以它使用一个普通的指针。二叉树(具有值语义)拥有其子级的唯一所有权,因此这些子级是std::unique_ptr

代码语言:javascript
复制
struct ListNode
{
    std::shared_ptr<ListNode> m_next;
    std::weak_ptr<ListNode> m_prev;
};

在这里,列表节点拥有它的下一个和前一个列表,所以我们定义了一个方向,并为next使用shared_ptr,为prev使用weak_ptr来打破这个循环。

票数 127
EN

Stack Overflow用户

发布于 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_ptrshared_ptr的通用优势和没有Boost依赖性使它们再次成为赢家。

作用域指针:与auto_ptr一样,unique_ptr使其无关紧要。

真的没什么好说的了。在没有移动语义的C++03中,这种情况非常复杂,但在C++11中,建议非常简单。

还有其他智能指针的用法,比如intrusive_ptrinterprocess_ptr。然而,它们是非常小众的,在一般情况下完全没有必要。

票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8706192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档