1

Consider the following C++20 code; assume T to be non-movable and non-copyable:

struct Cell
{
    Cell(T&& instance) : obj(std::move(instance)) {}

private:
    T obj;
};

Cell cell(T{/* arguments */});

Is move elision guaranteed in the constructor of Cell?

If T were movable, would it be guaranteed that only the regular (non-move) constructor would be invoked?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Pavel Kirienko
  • 1,162
  • 1
  • 15
  • 31
  • Does this answer your question? [What has changed in C++17 in terms of MOVE elision](https://stackoverflow.com/questions/70185398/what-has-changed-in-c17-in-terms-of-move-elision) – Captain Giraffe Sep 09 '22 at 13:44
  • 1
    @OP This will not work because you're trying to initialize `obj` with `std::move(instance)` when `T` is neither copyable nor movable. – Jason Sep 09 '22 at 13:47
  • Why would you expect copy/move elision to be possible here? Would you expect it to be possible when calling a function `void f(T&& instance) { auto obj = std::move(instance); }` with `f(T{/*args*/})` as well or is there something special you see about constructors? – user17732522 Sep 09 '22 at 13:51
  • 1
    Anyway, short answer: A suitable constructor for move-construction must be usable and will be called once and this call must not be elided. Elision through reference binding is never possible. The only way to elide such a copy/move into a class member is by using aggregate initialization. I am sure there is a matching duplicate somewhere. – user17732522 Sep 09 '22 at 13:53

1 Answers1

2

Is move elision guaranteed in the constructor of Cell?

No, the parameter instance of Cell::Cell(T&& instance) is of rvalue reference type T&&, so there can be no move elision here. The parameter instance must bind to the materialized temporary T{/* arguments */}. Then, std::move(instance) will be used to direct initialize obj.

But note that obj(std::move(instance) won't work because you're trying to initialize obj with std::move(instance) when T is neither movable neither copyable. Demo

Jason
  • 36,170
  • 5
  • 26
  • 60