Reputation: 13
What happens when I create a unique pointer using the raw pointer of another unique pointer? In the example below, what would happen when create second class is called? I thought that first_obj_ would give up ownership when second_obj_ is created, but first_obj_ doesn't give up ownership when get is called.
class SecondClass {
SecondClass(Object* obj) : second_obj_(obj) {}
.....
private:
std::unique_ptr<Obj> second_obj_;
}
class FirstClass {
FirstClass() {
std::unique_ptr<Obj> first_obj_ = std::make_unique<Obj>();
}
std::unique_ptr<SecondClass> CreateSecondClass() {
std::make_unique<Obj>(first_obj_.get());
}
.....
private:
std::unique_ptr<Obj> first_obj_;
SecondClass second_class;
}
Upvotes: 0
Views: 2107
Reputation: 22304
You should use release()
if you want to give up ownership.
std::unique_ptr
cannot know what you will do with the pointer extracted with get()
and in particular it cannot know that you decided to give it to another std::unique_ptr
.
If two std::shared_ptr
s will store the same pointer, you will get double delete
of the object, which is Undefined Behaviour.
However, if you want to pass ownership from one std::unique_ptr
to another, you should probably use move semantics instead:
class Obj {};
struct SecondClass {
SecondClass(std::unique_ptr<Obj>&& obj) : second_obj_(std::move(obj)) {}
private:
std::unique_ptr<Obj> second_obj_;
};
struct FirstClass {
FirstClass() {
first_obj_ = std::make_unique<Obj>();
}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(std::move(first_obj_));
//note that first_obj_ points to nullptr now. Only SecondClass owns the Obj.
}
private:
std::unique_ptr<Obj> first_obj_;
};
Upvotes: 1
Reputation: 596713
What happens when I create a unique pointer using the raw pointer of another unique pointer?
BAD THINGS CAN HAPPEN!
You end up with 2 unique_ptr
objects that both think they are the exclusive owner of the raw pointer, and so both objects will try to manage and ultimately free the owned memory. To avoid that, you have to pass ownership from one unique_ptr
to the other, or else give at least one of the unique_ptr
s a custom deleter
that does not free the memory (in which case, you shouldn't be using 2 unique_ptr
objects to begin with).
In the example below, what would happen when create second class is called?
Both first_obj_
and second_obj_
end up holding pointers to the same Object
in memory, and both of them will try to delete
it.
I thought that
first_obj_
would give up ownership whensecond_obj_
is created
No, because unique_ptr::get()
simply returns a copy of the raw pointer, it does not release ownership of the pointer. If you want that, use unique_ptr::release()
instead:
class SecondClass {
public:
SecondClass(Object* obj) : second_obj_(obj) {}
...
private:
std::unique_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_unique<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(first_obj_.release());
}
...
private:
std::unique_ptr<Object> first_obj_;
};
Otherwise, you can simply std::move
one unique_ptr
into the other:
class SecondClass {
public:
SecondClass(std::unique_ptr<Object> obj) : second_obj_(std::move(obj)) {}
...
private:
std::unique_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_unique<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(std::move(first_obj_));
}
...
private:
std::unique_ptr<Object> first_obj_;
};
If you truly want FirstClass
and SecondClass
to share the same pointer, then use std::shared_ptr
instead of std::unique_ptr
:
class SecondClass {
public:
SecondClass(std::shared_ptr<Object> obj) : second_obj_(obj) {}
...
private:
std::shared_ptr<Object> second_obj_;
};
class FirstClass {
public:
FirstClass() : first_obj_(std::make_shared<Object>()) {}
std::unique_ptr<SecondClass> CreateSecondClass() {
return std::make_unique<SecondClass>(first_obj_);
}
...
private:
std::shared_ptr<Object> first_obj_;
};
Upvotes: 2