I'd like to understand the cause of double envoking of copying-constructor in the following code:
#include <vector>
#include <thread>
#include <algorithm>
#include <functional>
#include <iostream>
#include <mutex>
std::mutex m_stdout;
class MyWorker {
public:
MyWorker() = default;
MyWorker(const MyWorker& mw) {
m_stdout.lock();
std::cout << "MyWorker coping" << std::endl;
m_stdout.unlock();
}
void operator() () {}
};
int main () {
std::vector<std::thread> vth;
vth.reserve(4);
MyWorker mw;
for (int i = 4; i > 0; --i) {
vth.emplace_back(mw);
}
std::for_each(vth.begin(), vth.end(), std::mem_fn(&std::thread::join));
}
stdout:
MyWorker coping
MyWorker coping
MyWorker coping
MyWorker coping
MyWorker coping
MyWorker coping
MyWorker coping
MyWorker coping
emplace_back
should not make two copies, should it?
This is really subtle: you need a move constructor. Basically, it DOES copy in once into the vector when you're making the thread, but then when the threads LAUNCH, they need to either copy or move their arguments in. You only have a copy constructor, so that's what it uses. I added this code below to demonstrate:
MyWorker(MyWorker&& mw) {
m_stdout.lock();
std::cout << "MyWorker moving" << std::endl;
m_stdout.unlock();
}
Add that in addition to the copy constructor you already have and you'll get this output:
MyWorker copying
MyWorker moving
MyWorker copying
MyWorker moving
MyWorker copying
MyWorker moving
MyWorker copying
MyWorker moving
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With