std::shared_ptr: reset() vs. assignment

When using reset() the parameter passed to reset need not be a managed object (nor can it be); whereas with = the right hand side must be a managed object.

So these two lines give you the same end result:

p = std::make_shared<int>(5); // assign to a newly created shared pointer
p.reset(new int(5)); // take control of a newly created pointer

But we cannot do:

p = new int(5); // compiler error no suitable overload
p.reset(std::make_shared<int>(5).get()); // uh oh undefined behavior

Without reset() you would not be able to reassign a shared pointer to a different raw pointer without creating a shared pointer and assigning it. Without = you wouldn't be able to make a shared pointer point to another shared pointer.


It's possible for reset to avoid a dynamic memory allocation in certain cases. Consider the code

std::shared_ptr<int> p{new int{}};  // 1
p.reset(new int{});                 // 2

On line 1 there are 2 dynamic memory allocations happening, one for the int object and a second one for the shared_ptr's control block that'll keep track of the number of strong/weak references to the managed object.

On line 2 there is again a dynamic memory allocation for a new int object. Within the body of reset the shared_ptr will determine that there are no other strong references to the previously managed int, so it must delete it. Since there aren't any weak references either, it could also deallocate the control block, but in this case it would be prudent for the implementation to reuse the same control block because it would otherwise have to allocate a new one anyway.

The above behavior would not be possible if you always had to use assignment.

std::shared_ptr<int> p{new int{}};    // 1
p = std::shared_ptr<int>{new int{}};  // 2

In this case, the second call to the shared_ptr constructor on line 2 has already allocated a control block, so p will have to deallocate its own existing control block.