Skip to content

Trivia impact: real

The Object That Cannot Be Moved

deleted copy and move constructors, yet a returned object

struct Locked {
  Locked() { std::cout << "made\n"; }
  Locked(const Locked&) = delete;
  Locked(Locked&&) = delete;
};

Locked make() {
  return Locked{};
}

Locked value = make();

Can a factory return an object that cannot be copied or moved?

Answer
made

Yes. It compiled and constructed the object exactly once.

Why

In C++17, the prvalue Locked{} directly initializes the result object of make, and that result directly initializes value. [dcl.init.general] makes those prvalue initializations guaranteed — "if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same as the destination type, the initializer expression is used to initialize the destination object" — so no copy or move constructor is selected at either step. This is not the optional elision of [class.copy.elision]: returning a named local still relies on an optimization the compiler is permitted, but never required, to perform.

Where it shows up

Factories can naturally return non-copyable resources, including types that contain a mutex. The C++17 rule removes a formerly common reason to add a move constructor solely to make a direct prvalue return compile.

Takeaway: A C++17 prvalue can initialize its destination without a copy or move.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry