The code bellow compiles and works as expected.
The structure (class) A
derives from std::thread
and expands with an int
more.
The main
code creates some threads and afterwards waits them to finish.
The problem is that while the code compiles without a destructor in struct A
, when the destructor is uncommented ( ~A(){}
) I get:
error: use of deleted function ‘std::thread::thread(const std::thread&)'
and I have no idea on why.
Moreover I don't understand why the code works both with push_back
and with emplace_back
while according to what I understand it shouldn't work with push_back
.
#include <iostream>
#include <thread>
#include <vector>
struct A : std::thread {
int i;
A(void f(const char*),const char* s,int i_) : std::thread{f,s},i{i_}{
std::cout<<"A created"<<std::endl;
}
//~A(){} // uncomment to see error
};
void dosomething(const char* s){
std::cout<<s<<std::endl;
}
int main(){
std::vector<A> aa;
aa.emplace_back(&dosomething,"hi people",3434);
aa.push_back(A(&dosomething,"hi again people",777));
aa.emplace_back(&dosomething,"hi again people",777);
aa.push_back(A(&dosomething,"hi again people",777));
for(auto& i:aa) i.join();
}
If you want the destructor, you can fix your code by adding
A(A &&) = default;
to reinstate the implicit move ctor.
Your first problem is that adding the user-defined destructor disables implicit generation of the move constructor.
The (misleading) error you see is the STL trying to fall back on copying types that can't be moved, and failing because std::thread
is deliberately non-copyable.
See this cppreference page's section on the Implicitly-declared move constructor, and this other question for some related motivation.
The second source of confusion is that push_back
has a move overload, so your original code was never copying in the first place, only moving. If you want to prove this, comment the dtor back out so it works again, and then try to push_back
a const reference to an A
. It will complain about the copy constructor, meaning the other push_back
calls aren't using that.