Rule A20-8-6 (required, implementation, automated)

std::make_shared shall be used to construct objects owned by std::shared_ptr.

Rationale

std::shared_ptr manages two entities: a control block (for meta data such as reference

counter or type-erased deleter) and an allocated object. Using std::make_shared typically performs a single heap allocation (as it is recommended by the Standard) for both control block and allocated object. std::make_shared function also provides object allocation without explicit call of new function, see A18-5-2. It also ensures exception safety and prevents from memory leaks caused by unspecified-evaluation-order expressions.

Exception

It is allowed to use explicit new function call to create an instance of std::shared_ptr, if it requires a custom deleter. It is also allowed to construct objects owned by std:: shared_ptr using std::allocate_shared.

Example

// $Id: A20-8-6.cpp 308507 2018-02-21 13:23:57Z michal.szczepankiewicz $
#include <memory>
#include <cstdint>
#include <functional>

struct A
{
A() { throw std::runtime_error("example"); }
A(std::uint8_t xx, std::uint8_t yy) : x(xx), y(yy) {}
std::uint8_t x;
std::uint8_t y;
};

void Foo(std::shared_ptr<A> a, std::shared_ptr<A> b) { }

int main(void)
{
//compliant
std::shared_ptr<A> upA = std::make_shared<A>(4,6);
//non-compliant
std::shared_ptr<A> upA2 = std::shared_ptr<A>(new A(5,7));

//non-compliant, potential memory leak, as A class constructor throws
Foo(std::shared_ptr<A>(new A()), std::shared_ptr<A>(new A()));
//non-compliant, potential memory leak, as A class constructor throws
Foo(std::make_shared<A>(4,6), std::shared_ptr<A>(new A()));
//compliant, no memory leaks
Foo(std::make_shared<A>(4,6), std::make_shared<A>(4,6));

//compliant by exception
std::shared_ptr<A> ptr(new A(4,5), [](A* b) { delete b; } );

return 0;
}

See also

C++ Core Guidelines [11]: R.22: Use make_shared() to make shared_ptrs. C++ Core Guidelines [11]: C.151: Use make_shared() to construct objects owned by shared_ptrs