why std::thread can be returned with not copyable limitation?

95 Views Asked by At

I'm quite confused about the successful compilation of the code below. The variable 't' in the function 'g' is obviously a left-value. When 'g' returns to the main function, 't' should be copied. However, the thread object is not copyable, so why does it compile successfully?

#include <thread>

void some_other_function(int) {
    return;
}
std::thread g()
{
    std::thread t(some_other_function,42);
    return t;
}

int main() {
    g();
    return 0;
}
2

There are 2 best solutions below

1
interjay On BEST ANSWER

When you return a local variable, the move constructor will be used instead of the copy constructor (if available). While std::thread does not have a copy constructor, it does have a move constructor so this will work.

See Automatic_move_from_local_variables_and_parameters

It's also possible that the compiler will elide the move completely due to NRVO (named return value optimization), but this isn't guaranteed.

6
Jan Schultke On

The code compiles because of Named Return Value Optimization (NRVO), or the implicit move that takes place if it cannot be performed. Regardless of which happens, the copy constructor won't be used.

This technique is possible whenever you return a local variable by name, like:

return t;

in your example. It is possible to treat the local object t as if it was the returned object outside of the function, so no move or copy constructor is called. As said above, if NRVO cannot be performed by the compiler, the move constructor is a fallback. std::thread is non-copyable, but movable, so this code works.

Note: your code would fail to compile for classes that are neither copyable nor movable, like std::mutex.