34

I just realised reading this page that the constructor of std::shared_ptr with a single pointer argument is not noexcept.

Hence the following code contains a possible memory leak:

std::shared_ptr<int> p3 (new int);

The reasonning is that two allocations could occure:

  • The first one before the call to the constructor
  • The second one in the constructor of shared_ptr (This is what happens in VS 2012 for example)

Two questions here:

Is it true that if the second allocation throws an exception, the memory of the first one leaks ?

If the answer is yes:

what is the correct idiom to use std::shared_ptr?

  • using make_shared
  • giving the ownership of the first allocation to a std::unique_ptr then transfering the ownership
  • Other thoughts ?
Enlico
  • 23,259
  • 6
  • 48
  • 102
Arnaud
  • 3,765
  • 3
  • 39
  • 69

2 Answers2

32
template<class Y> explicit shared_ptr(Y* p);

[util.smartptr.shared.const]/6 Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained.
[util.smartptr.shared.const]/7 Exception safety: If an exception is thrown, delete p is called.

So no, no memory leak.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
12

Late answer, but it is better to use make_shared() for exception safety, as outlined in GotW #102: The following code is not exception safe:

 f( std::shared_ptr<T1>{ new T1 }, std::shared_ptr<T2>{ new T2 } );

Whereas the following is:

f( std::make_shared<T1>(), std::make_shared<T2>() );
Thomas McGuire
  • 5,308
  • 26
  • 45
  • Also, the replacement is potentially more efficient. – Deduplicator Nov 19 '15 at 20:34
  • There are cases where you cannot use `make_shared`, namely calling new on an inherited type while `shared_ptr` is templated to hold the base type. – sebkraemer Apr 09 '18 at 14:24
  • A bit late for the party, but I was here for another use-case when that's not possible: when you need to specify a custom deallocator. But there is an easy workaround: never call std::shared_ptr{} multiple times in the same statement. – Michaël Roy Sep 12 '18 at 18:51
  • 4
    Another case where you may **not** want to use a std::make_shared() : if weak_ptr that would outlive the shared_ptr are obtained from an shared_ptr made with std::make_shared(), **the memory occupied by your object T will persist until all weak owners get destroyed as well**. (Why ? std::make_shared is - in practice - more efficient than the shared_ptr constructor, because it do only **one allocation** for **both** the object T and the control block instead of two. The weak_ptr needs the control block, so you're then stuck with this monolithic block.) – Adrian B. Jan 21 '21 at 22:32