I have some calculation I need to perform that is dependent on two or more steps as follows:
class A
{
public:
double step1() { return 2.5; }
};
class B
{
public:
double step2() { return 1.2; }
};
class Result
{
public:
Result(std::shared_ptr<A> _a, std::shared_ptr<B> _b) : a(_a), b(_b) {};
double getResult() { return a->step1() + b->step2(); }
private:
std::shared_ptr<A> a;
std::shared_ptr<B> b;
};
In actuality, step 1 and step 2 need polymorphic behavior, so these (shared) pointers would be to the "interface" class, but that detail isn't important here.
Now, the final calculation in getResult()
also needs polymorphic behavior, so I create a (unique) pointer to Result
, create a lambda calling getResult()
, and pass that lambda to my threads like so:
void run_multi_threaded_calculation()
{
auto result = create_result_unique_ptr();
const int nThreads = 4;
std::vector<double> save(nThreads);
auto task = [&](int n) {
// Preprocessing before getResult()
save[n] = n * result->getResult();
};
std::vector<std::thread> threads;
threads.reserve(nThreads);
for (size_t i = 0; i < nThreads; ++i)
{
threads.push_back(std::thread(task, i));
}
for (auto& th : threads)
th.join();
for (const auto& s : save)
std::cout << s << '\n';
}
Question 1: Am I using the correct configuration of smart pointers and lambda capture, e.g. unique_ptr
to Result
and shared_ptr
to A
and B
? After some guess and check changing smart pointer types the above compiles (but does not compile if a
and b
in Result
are unique_ptr
's), but I'm not sure if this is the best way to approach this.
Question 2: If I replace the lambda with an equivalent (or so I thought) function object, then my code does not compile (Error C2661: 'std::tuple<ResultFunctor,unsigned int>::tuple': no overloaded function takes 2 arguments). Is there something I'm missing with smart pointers, or maybe the way threads work, or possibly some issue with my function object definition?
Here's the relevant changes:
class ResultFunctor
{
public:
ResultFunctor(std::unique_ptr<Result> _result, std::vector<double>& _save) : result(std::move(_result)), save(_save) {};
void operator() (int n) { save[n] = n * result->getResult(); }
private:
std::unique_ptr<Result> result;
std::vector<double>& save;
};
and replace the following line:
void run_multi_threaded_calculation()
{
// Other stuff is unchaged...
/*auto task = [&](int n) {
// Preprocessing before getResult()
save[n] = n * result->getResult();
};*/
auto task = ResultFunctor(std::move(result), save);
// other stuff is unchanged...
}