用std::vector替换shared_ptr元素

3
我有一个如下所示的shared_ptr向量。
std::vector<std::shared_ptr<SharedThing>> things;

现在假设我将多个shared_ptr推入向量中,每个元素现在的引用计数为1。
当我需要使用新的shared_ptr替换其中一个元素时,我希望旧的shared_ptr超出范围。常规元素赋值会实现这一点,还是只会复制shared_ptr内容?例如:
things.at(0) = new_shared_ptr;

这会减少things.at(0)的引用计数并增加new_shared_ptr的计数吗?

使用调试器来证明这一点。 - Ed Heal
2
http://en.cppreference.com/w/cpp/memory/shared_ptr/operator%3D - GManNickG
2个回答

3

当我需要用新的shared_ptr替换其中一个元素时,我希望旧的shared_ptr不再使用。常规的元素赋值能实现这个吗?

vector中的shared_ptr不会失效,但它将用给定的新对象替换被管理的对象。

调用:

things.at(0) = new_shared_ptr;

这将保留计数为1。

下面是观察此行为的简单方法:

#include <iostream>
#include <vector>
#include <memory>

int main(){

  //vector with a shared pointer
  std::vector<std::shared_ptr<int>> things;
  things.push_back(std::make_shared<int>(1));

  //prints 1
  std::cout << things.at(0).use_count() << '\n';

  //assign a new value
  things.at(0) = std::make_shared<int>(2);

  //still prints 1
  std::cout << things.at(0).use_count() << '\n';
}

虽然这不是你的问题的一部分,但通常建议使用make_shared而不是new


1
这不是“保留计数”,你正在从一个完全不同的对象中读取计数。(使用计数不是shared_ptr的一部分,而是目标对象的元数据块的一部分) - Ben Voigt

2

是的,基本上你是正确的。
更准确地说,前一个shared_ptr在at(0)的引用计数将会被减少。然后你用一个新的shared_ptr赋值给它,这个shared_ptr可能有1的计数。看起来at(0)的引用计数是相同的,但它已经改变了并且又改变回来了。

你可以通过std::shared_ptr::use_cout()进行验证。

要获取更多细节,我们可以调试STL,当things.at(0) = new_shared_ptr;

include/c++/4.8.3/bits/shared_ptr_base.h:556

  __shared_count&
  operator=(const __shared_count& __r) noexcept
  {    
_Sp_counted_base<_Lp>* __tmp = __r._M_pi;
if (__tmp != _M_pi)
  {    
    if (__tmp != 0)
      __tmp->_M_add_ref_copy();
    if (_M_pi != 0)
      _M_pi->_M_release();
    _M_pi = __tmp;
  }    
return *this;
  }    

新的函数为_M_add_ref_copy(),之前的函数为_M_release(),它会将_M_use_count减1。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接