14

Are there any differences between the two pieces of code below? Is any of them preferable to the other?

operator=

boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo = boost::shared_ptr<Blah>(new Blah()); // Involves creation and copy of a shared_ptr?

reset

boost::shared_ptr<Blah> foo; // foo.ptr should be NULL
foo.reset(new Blah()); // foo.ptr should point now to a new Blah object

Note: I need to define the shared_ptr and then set it in a different line because I'm using it in a piece of code like:

boost::shared_ptr<Blah> foo;
try
{
  foo.reset...
}
foo...
csl
  • 10,937
  • 5
  • 57
  • 89
rturrado
  • 7,699
  • 6
  • 42
  • 62

4 Answers4

17

operator= assigns a shared_ptr to a shared_ptr, while reset makes a shared_ptr take ownership of a pointer. So, basically there is no difference between the examples you have posted. That said, you should prefer neither of them and just use make_shared:

foo = boost::make_shared<Blah>();

Also, if possible, you can prevent having to declare a shared_ptr without initialization by wrapping the try-catch block in a separate function that simply returns a shared_ptr to the newly created object:

boost::shared_ptr<Blah> createBlah() {
    try {
        // do stuff
        return newBlah;
    }
    catch ...
}
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • Can you please justify your comment that make_shared should be preferred? – Jon Mar 14 '13 at 20:01
  • Building on object using `new` and initializing a `shared_ptr` with it is a two-step process. In theory, creating the object could succeed, but initializing the `shared_ptr` could fail, in which case you would leak memory, unless you explicitly handle that case. `make_shared` takes care of that for you. According to the [documentation](http://www.boost.org/doc/libs/release/libs/smart_ptr/make_shared.html), it is also faster. – Björn Pollex Mar 14 '13 at 20:10
3

operator= takes another shared_ptr as a parameter thus creating another copy (and upping the reference count) while reset() takes a pointer and optionally a deleter, thus in reality creating a new shared_ptr on top of the current one.

reset is equivalent to (and probably implemented as)

void reset(T p, D d)
{
   shared_ptr shared(p,d);
   swap( shared );
}

operator= is likely to be implemented as:

shared_ptr& operator=( shared_ptr const& other )
{
   shared_ptr shared(other);
   swap(other);
   return *this;
}

The two functions are similar in that they release control of what they are already containing, if any, and manage a different pointer instead.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • 1
    `reset` is also overloaded to take another shared pointer, in which case it is equivalent to assignment. – Mike Seymour Mar 18 '11 at 12:42
  • CashCow: could you explain the role of the line `shared_ptr shared(other);` in your implementation of `operator=`? – freitass Jun 07 '13 at 11:48
2

foo.reset(p) is defined to be equivalent to shared_ptr(p).swap(foo).

Assignment is logically equivalent to copy-and-swap, and possibly implemented that way. So foo = shared_ptr(p); is equivalent to foo.swap(shared_ptr(p)). Possibly with an extra copy in there if the compiler is having a very bad day.

So in the examples you give, I don't think there's much to choose between them. There might be other cases where it matters. But reset does the same template-based capture of the static type of p that the template constructor does, so as far as getting the right deleter is concerned, you're covered.

The main use of assignment is when you want to copy a previously-existing shared_ptr, to share ownership of the same object. Of course it works fine when assigning from a temporary too, and if you look at the different reset overloads they mirror the different constructors. So I suspect you can achieve the same things either way.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
0

Assignment operator create a new shared object from existing one, incrementing the reference count

CSharedObj& CSharedObj::operator=(CSharedObj& r) noexcept
{ 
     if(*this != r){
        //detach from the previous ownership
        if(0 == dec()) delete m_pControlObj;
        //attach to the new control object and increment the reference count
        r.inc();
        m_pControlObj = r.m_pControlObj;
    }
    return *this;
}

while the reset call doesn't create the new shared object, but rather a new ownership - attaching to the new underlying pointee ( via control object)

void CSharedObj::reset(Ptr pointee) noexcept
{
   //check if this is a last reference-detach from the previous ownership
   if(0==dec()) delete m_pControlObj;
   // create the ownership over the new pointee (refCnt = 1)
   m_pControlObj = new (std::nothrow) CControlObj(pointee);
}
damirlj
  • 85
  • 1
  • 2