简体   繁体   中英

Replacing shared_ptr elements in std::vector

I have a vector of shared_ptrs as below.

std::vector<std::shared_ptr<SharedThing>> things;

Now let's say I push a number of shared_ptrs onto the vector and each element now has a reference count of 1.

When I need to replace one of those elements with a new shared_ptr I want the old shared_ptr to go out of scope. Will regular element assignment achieve this or will it just copy the shared_ptr contents. For example:

things.at(0) = new_shared_ptr;

Will this decrement the reference count of things.at(0) and increment the count of new_shared_ptr?

When I need to replace one of those elements with a new shared_ptr I want the old shared_ptr to go out of scope. Will regular element assignment achieve this?

The shared pointer in the vector won't go out of scope,
but it will replace the managed object with the new one given.

Calling:

things.at(0) = new_shared_ptr;

will preserve the count at 1.

Here is an easy way to observe this behaviour:

#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';
}

Although not a part of your question, it is often advised to use make_shared instead of a new .

Yes, basically you are right.
To be more accurate, the reference count of previous shared_ptr at(0) will be decremented. And then you assign it with a new shared_ptr, which may have the count 1. Looks like the reference count at(0) is the same, but it changed and changed back.

You can verify it by std::shared_ptr::use_cout()

For more details, we can debug into the STL, when 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;
  }    

The new one _M_add_ref_copy(), then previous one _M_release(), which will decrease the _M_use_count by 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM