c++movemove-semanticsvalue-categories

In C++, what happens under the hood when an rvalue of a move-only type is passed to a function by value?


I am trying to understand value categories in C++ a bit better, and I encountered some code that got me a bit confused.

I looked at some questions such as Accept move-only parameter by value or rvalue reference or How is it possible to pass move-only types (e.g. std::unique_ptr) by value?, but I did not find any comment explaining what happens under the hood or why it is possible to pass as arguments rvalues of move-only types by value. Take the example below:

class Foo
{
  Foo(std::thread t) : mT(std::move(t))
private:
  std::thread mT;
};

int main()
{
  std::thread t;
  Foo f(t); // doesn't compile as std::thread is not copyable
  Foo f{std::thread()}; // compiles just fine using an rvalue
}

Calling Foo f(t); would call the non-existent copy-constructor of std::thread. However, what happens under the hood for the same not to happen when constructing a Foo object with the rvalue std::thread()? Why is the rvalue not copied?


Solution

  • Why is the rvalue not copied?

    The expression std::thread() is the initialisation of the parameter t. It is the same as why there isn't a copy when you write std::thread t;.

    In the implementation of Foo::Foo, the object t is passed to std::move, which casts it to an rvalue reference, so that it matches std::thread::thread(std::thread&&), i.e. thread's move constructor.