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