最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - RVO with deleted constructor - Stack Overflow

programmeradmin1浏览0评论
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?

Share Improve this question edited Feb 7 at 23:13 Bruce asked Feb 7 at 23:02 BruceBruce 35.3k77 gold badges182 silver badges266 bronze badges 5
  • @NathanOliver fixed. The code still works if they are private :) – Bruce Commented Feb 7 at 23:15
  • 2 You're never calling make-unique, or initializing your unique pointer with a raw pointer. The unique pointer returned will be a null pointer and no construction is used or needed – Neil Butcher Commented Feb 7 at 23:16
  • 1 This is more to do with std::unique_ptr than your class. If you attempt to return using std::make_unique(), you'll see your error. – sweenish Commented Feb 7 at 23:17
  • for RVO it isnt relevant whether Foo can be moved or copied, you return a std::unique_ptr<Foo>. To move a unique_ptr the contained Foo does not need to move or copy. – 463035818_is_not_an_ai Commented Feb 7 at 23:18
  • Your code is equivalent to class Foo{}; int main() { Foo* result = nullptr; } – Eljay Commented Feb 7 at 23:45
Add a comment  | 

2 Answers 2

Reset to default 7

A 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.

发布评论

评论列表(0)

  1. 暂无评论