У меня есть некоторый расчет, который мне нужно выполнить, который зависит от двух или более шагов следующим образом:
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;
};
На самом деле шаг 1 и шаг 2 требуют полиморфного поведения, поэтому эти (общие) указатели будут указывать на класс интерфейса, но эта деталь здесь не важна.
Теперь окончательный расчет в getResult()
также требует полиморфного поведения, поэтому я создаю (уникальный) указатель на Result
, создаю лямбду, вызывающую getResult()
, и передаю эту лямбду в свои потоки следующим образом:
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';
}
Вопрос 1. Использую ли я правильную конфигурацию интеллектуальных указателей и лямбда-захвата, например unique_ptr
к Result
и shared_ptr
к A
и B
? После некоторых предположений и проверки изменения типов интеллектуальных указателей вышеуказанное компилируется (но не компилируется, если a
и b
в Result
являются unique_ptr
), но я не уверен, что это лучший способ подойти к этому.
Вопрос 2: Если я заменю лямбду эквивалентным (или так я думал) функциональным объектом, мой код не скомпилируется (ошибка C2661: 'std::tuple‹ResultFunctor,unsigned int›:: tuple': ни одна перегруженная функция не принимает 2 аргумента). Есть ли что-то, чего мне не хватает в интеллектуальных указателях, или, может быть, в том, как работают потоки, или, возможно, какая-то проблема с определением моего функционального объекта?
Вот соответствующие изменения:
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;
};
и замените следующую строку:
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...
}
result
должен быть указателем? - person Paul Sanders   schedule 20.07.2020Result
вести себя полиморфно, производная от чего-то вродеIResult
базового класса. ЗатемgetResult
будет использовать шаги 1 и 2, но с некоторыми другими вычислениями. - person Charlie H.   schedule 20.07.2020step1() /*... Do some stuff with the result...*/ step2()
. - person Charlie H.   schedule 22.07.2020