Typically if you are using a std::shared_ptr
to point to an object and you want to create another pointer to that object that does not share ownership you would create a std::weak_ptr
.
// Create a shared pointer to own the object
std::shared_ptr<int> p = std::make_shared<int>(42);
// Create a weak pointer (that does not own the object)
std::weak_ptr<int> q(p);
// Use the weak pointer some time later
if (std::shared_ptr ptr = q.lock()) {
// use *ptr
}
My question is, how do you do this when it comes to std::unique_ptr
?
Using a unique pointer ensures that the current resource is owned exclusively by the std::unique_ptr
itself. But what if I want to create a pointer to the same resource that does not own that resource? I can't use a std::weak_ptr
because weak pointers are designed to work with the reference count from a std::shared_ptr
. Would I just use a raw pointer here? Or is there a better alternative?
// Create a unique pointer to own the object
std::unique_ptr<int> p = std::make_unique<int>(42);
// Create a non-owning pointer to the same object
// Is this really the best way?
int* q = p.get();
// Use the pointer some time later
if (q != nullptr) {
// Imagine this may be multithreaded...
// what happens if p.reset() is called by another thread while the current thread is RIGHT HERE.
// use *q
}
The only way I can think of creating a non-owning pointer to an object owned by a std::unique_ptr
would be to use a raw pointer, but as you can see from the code above this may cause issues in threaded applications. Is there a better way to achieve the same goal?
Based on your last example, this is a scenario where std::shared_ptr
and std::weak_ptr
should be used.
std::unique_ptr
and a non-owning Raw Pointer should be used in the scenario where you have a guarantee that the smart pointer will outlive the raw pointer.
class A {
std::unique_ptr<int> ptr = std::make_unique<int>(5);
public:
int* get_ptr() const{return ptr.get();}
};
class B {
A a;
public:
void do_something() {
//int * ptr = a.get_ptr();//Valid, but not advised
int & ref = *a.get_ptr();//Preferred
ref++;
}
};
If you can make this guarantee, you should be using std::unique_ptr
and a raw pointer to represent this object. This is ideomatically correct.
If, however, you can't guarantee lifetime at the time you need to manipulate the object, then references should be provided by std::weak_ptr
, which are used to acquire ownership (even if only temporarily!) to make changes.
class A {
std::shared_ptr<int> ptr = std::make_shared<int>(5);
public:
std::weak_ptr<int> get_ptr() const {
return ptr;//Implicitly converts
}
void destroy() {
ptr.reset();
}
};
class B {
std::weak_ptr<int> ptr;
public:
B(std::weak_ptr<int> ptr) : ptr(ptr) {}
void do_something() {
if(auto owned_ptr = ptr.lock()) {//owned_ptr will be deduced to be of type std::shared_ptr<int>
*owned_ptr++; //Guaranteed to only execute if the pointer is still valid
}
}
};
int main() {
A a;
B b(a.get_ptr());
if(get_random_value() > 10)
a.destroy();
b.do_something();
}
unique_ptr
.unique_ptr
: Make it a plain pointer. Whoever gets this kind of pointer can assume it's valid, but cannot presume to own the memory it points to.unique_ptr
: Your original pointer is not really "unique"; and you should replace the unique_ptr
with a shared_ptr
and pass a weak_ptr
as the non-owning copy.I just noticed that this answer is basically a brief summary of Xirema's answer. Please upvote/accept that answer!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With