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?
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 astd::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 astd::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
tostd::unique_ptr
is not allowed. Once you’ve turned lifetime management of a resource over to astd::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 astd::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");
std::unique_ptr
to a std::shared_ptr
. –
Issiah std::unique_ptr
into a std::shared_ptr
? The standard library defines a move assignment operator template<class Y, class Deleter> shared_ptr& operator=(std::unique_ptr<Y, Deleter>&& r);
for std::shared_ptr<T>
. –
Wavell unique_ptr
to shared_ptr
works because shared_ptr
class has knowledge of unique_ptr
and it is equipped with both constructor and assignment operator that accept a rvalue reference
to unique_ptr
(the rvalue reference is essential because guarantees the unique_ptr
is not going to be used anymore). It is not std::move
that makes the magic, but shared_ptr
class. –
Broadfaced I would prefer to do this.
std::unique_ptr<int> up_ = std::make_unique<int>();
std::shared_ptr<int> sp_ = std::move(up_);
While converting from std::shared_ptr<T>
to std::unique_ptr<T>
is by design impossible (since it would allow std::unique_ptr<T>
's single-reference invariant to be violated), it's still possible to move the contents of a shared object into a new instance managed by a unique pointer. For example:
std::shared_ptr<std::string> shared = std::make_shared<std::string>("test");
std::unique_ptr<std::string> unique = std::make_unique<std::string>(std::move(*shared));
In the second line above, the contents of *shared
(i.e. the string managed by the shared
pointer) are moved into a new std::string
instance managed by the unique
pointer. The side-effect of this is that the std::string
object managed by shared
is left in a "valid but unspecified state", since it has been stripped of its contents. But since the whole point of making a managed object "unique" is to prevent it from being accessed from anywhere else, I would say this is actually in keeping with the spirit of the operation.
You can assign your shared-pointer to a unique-pointer.
A custom deleter may be provided, which allows ownership to be transferred.
While the custom deleter usually transfers ownership to the thing that will delete the pointer, the pointer may also be sent somewhere (anywhere) else. Using the custom deleter enforces the already obvious requirement that ownership only be transferred when the shared pointer itself is going out of scope.
Here is a minimal example:
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int> up;
{
std::shared_ptr<int> sp = std::shared_ptr<int>(new int (42),
[&up] (int* ptr) {up = std::unique_ptr<int>(ptr); });
}
std::cout << "Unique-ptr = " << *up << "\n";
}
Disclaimer: I make no comments as to whether or not this is a terrible idea!
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.
(As many people have noted, there is more to this story, and it's worth reading the comments.)
std::shared_ptr<whatever> s_ptr(std::move(u_ptr));
–
Saltzman std::shared_ptr<whatever> s_ptr{std::move(u_ptr)};
–
Saturn Deleter
stored inside the unique_ptr
–
Kenleigh shared_ptr
and unique_ptr
were introduced with C++11. –
Linnealinnean © 2022 - 2025 — McMap. All rights reserved.
shared_ptr
. – Stibnite