With C++ smart pointers there is a lot of space for unexperienced programmer to run into double free and doing things that are semantically wrong.
Some examples:
-You can create a raw pointer and initialize two different unique_pointer. (double free).
-You can create a raw pointer and initialize two different shared_pointer. (double free + wrong count).
-You can bind a raw pointer to both a unique and a shared_pointer. (double free and semantically incorrect).
None of these have been a practical problem since C++14, which introduced `std::make_unique`. (`std::make_shared` has always existed.)
To heap-allocate something managed by a smart pointer, all you have to do is
auto p = std::make_shared<Widget>(1,2,3);
auto q = std::make_shared<Widget>(4,5,6);
To point `p` at an existing heap-allocation:
p = std::move(q);
To point it at a new heap-allocation:
p = std::make_shared<Widget>(7,8,9);
My mantra for using smart pointers to manage ownership of heap-allocated objects is "Don't touch raw pointers with your hands."
HTH,
Arthur
P.S. — Admittedly you can still get into trouble by using some of the arcane named methods of the smart-pointer objects themselves:
p.release(); // memory leak
q.reset(r.get()); // double-free bug
But it's easy to grep your codebase for `.reset(` and `.release(`, just like you already grep for `reinterpret_cast` or `new ` or `volatile` or whatever other code smells you prefer to prohibit.