112

Does C++11 standard library provide any utility to convert from a std::shared_ptr to std::unique_ptr, or vice versa? Is this safe operation?

curiousguy
  • 7,344
  • 2
  • 37
  • 52
Hind Forsum
  • 8,077
  • 8
  • 40
  • 88
  • Define "safe operation" please. What sort of safety are you looking for? lifetime management safety? Thread safety? – jaggedSpire Jun 17 '16 at 15:05
  • 2
    "STL" doesn't mean standard library. The STL has nothing to do with `shared_ptr`. – curiousguy Dec 25 '16 at 01:39
  • 1
    @jaggedSpire Thread safety would mean you have owners used in different threads, i.e. the use count is not 1. – curiousguy Dec 25 '16 at 01:41
  • @curiousguy I knew that. My point was "safety" was not well defined in OP's question, and he needed to clarify which kind of "safety" he meant as there are multiple kinds. – jaggedSpire Dec 25 '16 at 03:17

2 Answers2

187

std::unique_ptr is the C++11 way to express exclusive ownership, but one of its most attractive features is that it easily and efficiently converts to a std::shared_ptr.

This is a key part of why std::unique_ptr is so well suited as a factory function return type. Factory functions can’t know whether callers will want to use exclusive ownership semantics for the object they return or whether shared ownership (i.e., std::shared_ptr) would be more appropriate. By returning a std::unique_ptr, factories provide callers with the most efficient smart pointer, but they don’t hinder callers from replacing it with its more flexible sibling.

std::shared_ptr to std::unique_ptr is not allowed. Once you’ve turned lifetime management of a resource over to a std::shared_ptr, there’s no changing your mind. Even if the reference count is one, you can’t reclaim ownership of the resource in order to, say, have a std::unique_ptr manage it.

Reference: Effective Modern C++. 42 SPECIFIC WAYS TO IMPROVE YOUR USE OF C++11 AND C++14. Scott Meyers.

In short, you can easily and efficiently convert a std::unique_ptr to std::shared_ptr but you cannot convert std::shared_ptr to std::unique_ptr.

For example:

std::unique_ptr<std::string> unique = std::make_unique<std::string>("test");
std::shared_ptr<std::string> shared = std::move(unique);

or:

std::shared_ptr<std::string> shared = std::make_unique<std::string>("test");
Toby Speight
  • 23,550
  • 47
  • 57
  • 84
chema989
  • 3,266
  • 2
  • 15
  • 29
  • Be aware that while not allowed the compiler (at least not gcc) will actually *not* prevent (or even warn) if you accidentally (e.g. by changing the pointer type of a member variable) assign a `std::unique_ptr` to a `std::shared_ptr`. – StefanQ Feb 20 '20 at 10:17
  • STL reference: https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr – Ida Sep 17 '20 at 09:38
  • 2
    @StefanQ What makes you think that it's not allowed to assign a `std::unique_ptr` into a `std::shared_ptr`? The standard library defines a move assignment operator `template shared_ptr& operator=(std::unique_ptr&& r);` for `std::shared_ptr`. – cuddlebugCuller Oct 18 '20 at 02:27
-9

Given unique_ptr u_ptr, create shared_ptr s_ptr:

std::shared_ptr<whatever> s_ptr(u_ptr.release());

Going the other way is impractical.

nmr
  • 15,900
  • 10
  • 49
  • 62
  • 32
    Here's the "right" way: `std::shared_ptr s_ptr(std::move(u_ptr));` – emlai Dec 25 '16 at 01:55
  • 9
    And here is the pedantic "right" way: `std::shared_ptr s_ptr{std::move(u_ptr)};` – polyvertex Nov 20 '17 at 17:06
  • @polyvertex: is there any actual difference between these two syntaxes in this particular case? – Violet Giraffe Mar 11 '18 at 22:24
  • 1
    @nmr's conversion is not wrong, just a bit not safer, so don't downvote his answer. I consider emlai's conversion the "right" way. – Stoica Mircea Jul 17 '18 at 12:18
  • 3
    What's less safe about it? – nmr Jul 17 '18 at 20:56
  • 8
    @VioletGiraffe • I suppose polyvertex is advocating using the new initialization list syntax — which avoids silent narrowing conversions and accommodates member initialization with a uniform syntax — as a good habit to get into. Six of one, half-dozen of the other? – Eljay Aug 16 '18 at 11:57
  • Initialization in C++ is a big fat mess, and it's finally getting fixed in C++20. We should all use the new uniform way. See: https://www.youtube.com/watch?v=9-_TLTdLGtc – Zendel Jan 24 '19 at 18:59
  • 11
    @nmr It is unsafe because you may lose the `Deleter` stored inside the `unique_ptr` – Zang MingJie Aug 19 '19 at 08:56
  • Would be the only pre C++11 way though, wouldn't it be? – Jimmy R.T. Mar 17 '20 at 11:53
  • @JimmyR.T. `shared_ptr` and `unique_ptr` were introduced with C++11. – Olaf Dietsche Mar 20 '20 at 10:57
  • @ZangMingJie Why "may lose" and not just "lose" ? I see no reason for compilers to recognize the intent and forward the deleter to the shared pointer in that situation. IMHO the custom deleter gets simply lost with nmr's solution, which is why the answer is not just "a bit not safer", but rather "dangerous" – Norman Pellet Jul 09 '20 at 13:51