Предположим, у меня есть вектор строк, и я хочу объединить их через std::accumulate.
Если я использую следующий код:
std::vector<std::string> foo{"foo","bar"};
string res="";
res=std::accumulate(foo.begin(),foo.end(),res,
[](string &rs,string &arg){ return rs+arg; });
Я могу быть уверен, что будет временное строительство объекта.
В этом ответе говорится, что эффект std::accumulate указан следующим образом:
Вычисляет результат, инициализируя аккумулятор acc начальным значением init, а затем изменяя его с помощью acc = acc + *i или acc = binary_op(acc, *i) для каждого итератора i в диапазоне [first, last) по порядку.
Поэтому мне интересно, как правильно это сделать, чтобы избежать ненужной конструкции временного объекта.
Одна из идей заключалась в том, чтобы изменить лямбду следующим образом:
[](string &rs,string &arg){ rs+=arg; return rs; }
В этом случае я решил принудительно объединить строки и помочь компилятору (я знаю, что должен 't) опустите ненужную копию, так как это должно быть эквивалентно (псевдокоду):
accum = [](& accum,& arg){ ...; return accum; }
и поэтому
accum = & accum;
Другая идея состояла в том, чтобы использовать
accum = [](& accum,& arg){ ...; return std::move(accum); }
Но это, вероятно, приведет к чему-то вроде:
accum = std::move(& accum);
Что мне кажется очень подозрительным.
Как правильно написать это, чтобы свести к минимуму риск ненужного создания временных объектов? Меня не просто интересует std::string, я был бы рад получить решение, которое, вероятно, будет работать для любого объекта, в котором реализованы конструкторы/назначения копирования и перемещения.
std::string
в качестве аккумулятора и, возможно,reserve
заранее. Хотя теперьaccumulate
уменьшено доfor_each
, и это ненамного лучше, чем решение Дэвида ниже. - person R. Martinho Fernandes   schedule 29.10.2013std::accumulate
всегда будет делать временные копии. Если это неприемлемо, то нужно использовать что-то другое. - person Mark Ransom   schedule 29.10.2013std::accumulate
не делает временных копий; этоoperator+
, который он вызывает, который делает дополнительную копию. (Кроме того,operator=
может закончиться копированием; с C++ и семантикой перемещения, скорее всего, этого не произойдет, но с более ранними версиями это произойдет.) - person James Kanze   schedule 30.10.2013acc = move(acc) + rhs
, что может значительно удешевить накопление типов, копирование которых обходится недешево. Например, хорошая реализацияstd::string
будет иметьoperator+(string&& lhs, T)
, который перехватываетlhs
, добавляет к нему и возвращает его (что является RVO-способным). @R.MartinhoFernandes Менее уродливым эквивалентом этого является накопление вreference_wrapper
, как в этом ответе, но да, я интересно, действительно ли это намного/лучше, чем простоfor[_each]
с захваченной ссылкой. Я думаю, может быть, немного, семантически? - person underscore_d   schedule 24.09.2018