class Foo {
public:
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
Foo() = delete;
};
std::unique_ptr<Foo> CreateFoo() {
return std::unique_ptr<Foo>();
}
int main(int argc, char** argv) {
std::unique_ptr<Foo> result = CreateFoo();
return 0;
}
Foo is not move constructible since the copy constructor/assignment operator is deleted. I have deleted the default constructor as well.
The code works fine and result is nullptr
at the end of main. I can see that RVO is applicable here so no copy/move constructor is necessary but I have deleted the default constructor as well. What's going on?
class Foo {
public:
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
Foo() = delete;
};
std::unique_ptr<Foo> CreateFoo() {
return std::unique_ptr<Foo>();
}
int main(int argc, char** argv) {
std::unique_ptr<Foo> result = CreateFoo();
return 0;
}
Foo is not move constructible since the copy constructor/assignment operator is deleted. I have deleted the default constructor as well.
The code works fine and result is nullptr
at the end of main. I can see that RVO is applicable here so no copy/move constructor is necessary but I have deleted the default constructor as well. What's going on?
2 Answers
Reset to default 7A default-constructed unique_ptr<T>
holds a null T*
pointer. It does not construct a new T
object.
So, none of your Foo
constructors are being called. CreateFoo()
is returning a unique_ptr
holding a null Foo*
pointer. So result
is initialized to null as well.
Had you coded CreateFoo()
to call std::make_unique<Foo>()
instead, that would be a different matter. Then you would get a compiler error trying to call a deleted Foo
constructor.
Your code essentially does nothing, that's why it doesn't have any errors.
std::unique_ptr<Foo> CreateFoo() {
return std::unique_ptr<Foo>();
}
returns an empty unique_ptr
, you don't actually allocate a Foo
object for it to point to. This is basically the same as doing return foo*{}
if you were working with raw pointers.
int main(int argc, char** argv) {
std::unique_ptr<Foo> result = CreateFoo();
return 0;
}
Here, all you do is get a copy of the empty pointer returned by CreateFoo()
, which is not an issue. It is like doing foo* result = {};
Change CreateFoo
to
std::unique_ptr<Foo> CreateFoo() {
return std::make_unique<Foo>();
}
and then you will get errors about not being able to construct the underlying Foo
object.
One last thing to note is that unique_ptr
is a perfect use case for types that can't be moved or copied. The object gets created in dynamic storage, and it always stays in that same place. It's just the pointer (handle) that you move around.
std::unique_ptr
than your class. If you attempt to return usingstd::make_unique()
, you'll see your error. – sweenish Commented Feb 7 at 23:17Foo
can be moved or copied, you return astd::unique_ptr<Foo>
. To move a unique_ptr the containedFoo
does not need to move or copy. – 463035818_is_not_an_ai Commented Feb 7 at 23:18class Foo{}; int main() { Foo* result = nullptr; }
– Eljay Commented Feb 7 at 23:45