Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why arguments moved twice when constructing std::thread

Consider this program that essentially creates std::thread that calls the function func() with arg as argument:

#include <thread>
#include <iostream>

struct foo {
   foo() = default;
   foo(const foo&) { std::cout << "copy ctor" << std::endl; }
   foo(foo&&) noexcept { std::cout << "move ctor" << std::endl; }
};

void func(foo){}

int main() {
   foo arg;
   std::thread th(func, arg);
   th.join();
}

My output is

copy ctor
move ctor
move ctor

As far as I understand arg is copied internally in the thread object and then passed to func() as an rvalue (moved). So, I expect one copy construction and one move construction.

Why is there a second move construction?

like image 997
Shaoyan Avatar asked Jan 05 '20 16:01

Shaoyan


People also ask

Why is std :: move necessary?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.

How does move constructor work c++?

Move constructor moves the resources in the heap, i.e., unlike copy constructors which copy the data of the existing object and assigning it to the new object move constructor just makes the pointer of the declared object to point to the data of temporary object and nulls out the pointer of the temporary objects.

What does default move constructor do?

A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying. For more information about move semantics, see Rvalue Reference Declarator: &&.

How to wait until thread is finished c++?

Waiting for threads to finish To wait for a thread use the std::thread::join() function. This function makes the current thread wait until the thread identified by *this has finished executing.


2 Answers

You pass argument to func by value which should constitute the second move. Apparently std::thread stores it internally one more time before calling func, which AFAIK is absolutely legal in terms of the Standard.

like image 50
bipll Avatar answered Sep 20 '22 15:09

bipll


So, I expect one copy construction and one move construction.

The standard doesn't actually say that. An implementation is allowed to do extra internal move constructions.

Doing so is potentially less efficient though. This was https://gcc.gnu.org/PR69724 and has been fixed for the upcoming GCC 10 release.

like image 22
Jonathan Wakely Avatar answered Sep 18 '22 15:09

Jonathan Wakely