如何遍历一系列shared_ptr对象?

时间:2013-06-24 23:33:47

标签: c++ c++11 reference shared-ptr

这更像是一种造型而非性能问题。我刚刚转换(大部分)指向shared_ptr对象的指针,并且不情愿地接受weak_ptrs作为原始指针的替代品。我的问题是,迭代共享指针对象的序列(比如说一个向量)的首选方法是什么?这是我一直在做的事情:

std::vector<std::shared_ptr<A>> my_sequence;
// Do something to fill my_sequence;

for (std::shared_ptr<A> const& ptr : my_sequence)
{
  ptr->AMethod();
}

这违反了*不要使用shared_ptr references *规则,那么什么是一个好的选择,为什么?

我会问的问题是;技术是否健全,即。对于AMethod()超小,my_sequence超大,这个方法会因shared_ptr副本而开始阻碍性能吗?它可读吗?这很简单吗?

2 个答案:

答案 0 :(得分:8)

不使用shared_ptr引用的原因是因为你击败了它试图保护自己的机制。即有一个潜在的悬挂指针。如果您正在迭代容器,这应该不是问题,因为对象不会意外地消失在您身上。您不应该存储以后可能使用的shared_ptr引用。

即。这很糟糕:

struct Y
{
    int y;
    Y() : y(1) {}
};

struct X
{
     shared_ptr<Y>& ref_shared_ptr_y;
     X(shared_ptr<Y>& y) : ref_shared_ptr_y(y) {}
};

void main()
{
    shared_ptr<Y> shared_ptr_y(new Y());
    X x(shared_ptr_y);
    y.reset();
    x.ref_shared_ptr_y->y;  // UB since x.ref_shared_ptr_y was deleted
}
只有在您确实需要在2个或更多位置之间共享对象所有权时,才应使用

shared_ptr。否则会导致不必要的开销,并表明您并未真正考虑过所有者关系。如果您的所有权仅限于一个位置,请使用unique_ptr

答案 1 :(得分:6)

首先,免责声明:

shared_ptr不是灵丹妙药。在实际共享所有权时应该使用它。非共享所有权由unique_ptr表示,非所有权由(原始)引用表示。 weak_ptrshared_ptr必须遵守但不归属的...... {但对于一般的过时指针来说,这不是一个很好的防御措施。默认为shared_ptr直接导致最低的共同点;这是糟糕的编程习惯。


此处的选择介于shared_ptr< T >shared_ptr< T const >shared_ptr< T > const &T const &T &之间。假设你没有改变任何东西,但序列可以改变它的对象,所以const是可取的。这会将其缩小为shared_ptr< T const >shared_ptr< T > const &T const &

让我们将问题重新表述为,

  

shared_ptr< T > const &是否是正确的选择?

从这个角度来看,评估替代方案。

  • shared_ptr< T const >(按值传递共享指针)

    • +:简单的价值语义;可以通过shared_ptr< T >
    • +:可以复制或move d扩展所有权池
    • +:将const正确性传播到被调用函数
    • +:对象的访问速度很快:包含直接指针参数
    • - :传递费用很高:复制两个机器字和原子触摸一个引用计数
    • - :被调用的函数关注所有权语义
  • shared_ptr< T > const &(通过引用传递共享指针)

    • +:传递与直接对象引用一样便宜
    • +:可以复制以扩展所有权池
    • - :对被调用函数

      失去const正确性
      • 如果您尝试使用shared_ptr< T const > const &,则会传递临时副本,最终会遇到此替代方案和按值传递的缺点。
    • - :对对象的访问通过额外的间接

    • - :被调用的函数关注所有权语义
  • T const &(直接参考)

    • +:保留const正确性
    • +:调用者不关心所有权语义
    • +:快速通过,只需一个机器字
    • +:访问快速,直接的指针参数到函数(如果是这样的话)
    • - :无法授予所有权

权衡它,如果没有扩展所有权(例如通过返回保留参数的对象),你真的应该传递一个简单的引用。在这种情况下,函数应该很少关心它的参数是如何拥有的。要求shared_ptr以最坏的方式违反关注点分离。您不能拥有本地对象或成员子对象,仍然可以使用该功能。最糟糕的是,一切都变得更加复杂。

如果所有权可能会扩展到其他人,这将是首先使用shared_ptr的理由,那么您应该始终传递shared_ptr< [const] T >值。是的,它会在通话时复制shared_ptr。但复制shared_ptr的昂贵部分是更新引用计数,而不是推送堆栈上的指针。如果您要授予所有权,则无论如何都要更新引用计数。获取传递的值move触及引用计数。完成后,你没有任何优势和许多缺点,无法通过引用传递。