Reputation: 775
I am having leaks in this piece of code. I know that I am passing objects to vector and to lambda function incorrectly, but I am not really sure how to solve that. Could you please give me any code review and correction?
std::vector<std::thread> threads;
std::vector<std::unique_ptr<FileHandler>> fileHandlers;
for (std::string argument : filesToParse)
{
std::unique_ptr<FileHandler> fileHandler(new FileHandler(argument));
fileHandlers.push_back(std::move(fileHandler));
threads.push_back(std::thread([&fileHandler]()
{
fileHandler->processFile();
}));
}
for(auto i = 0; i < threads.size(); ++i)
{
threads.at(i).join();
fileHandlers.at(i)->mergeMaps(finalMap);
}
Upvotes: 0
Views: 813
Reputation: 118445
There are several problems with the shown logic.
fileHandlers.push_back(std::move(fileHandler));
The contents of the fileHandler
unique_ptr have been moved away here. Immediately after this:
threads.push_back(std::thread([&fileHandler]() {
This passes, to each new thread, a reference to a unique_ptr
whose contents have just been moved away from. This unique_ptr
is gone to meet its maker. It ceased to exist. Joined the choir invisible. It's an ex-unique_ptr
.
fileHandlers.push_back(std::move(fileHandler));
Back to this statement. You get two logical errors for the price of one, here.
fileHandlers
is a vector. Adding a value to a vector may reallocate the vector. Reallocation invalidates all existing iterators, pointers, or references to the existing contents of the vector. Passing a reference to something in this vector, then subsequently adding something to this vector on the next iteration of the loop will blow up in your face if the vector reallocates.
The obvious intent here is to populate the fileHandlers
vector with a list of all parameters to all threads. There are two basic ways to do it correctly:
Use reserve()
to make sure that no reallocation subsequently occurs.
Populate the vector first, with all the values, and only then spawn off all the threads, passing to each thread a reference to its own parameter in the now-complete vector.
You have several ways to fix these problems:
Populate the vector first, or reserve its contents, then pass to each thread not the fileHandler
unique_ptr, but a reference to the unique_ptr
in the fileHandlers
array that has already been populated.
Alternatively, it's possible to avoid either reserving, or populating the vector in advance by switching to shared_ptr
s, and capturing by value each thread's shared_ptr
parameter.
Upvotes: 2