tach tach - 1 month ago 7x
C++ Question

Efficient accumulate

Assume I have vector of strings and I want concatenate them via std::accumulate.

If I use the following code:

std::vector<std::string> foo{"foo","bar"};
string res="";
[](string &rs,string &arg){ return rs+arg; });

I can be pretty sure there will be temporary object construction.

In this answer they say that the effect of std::accumulate is specified this way:

Computes its result by initializing the accumulator acc with the
initial value init and then modifies it with acc = acc + *i or acc =
binary_op(acc, *i) for every iterator i in the range [first,last) in

So I'm wondering what is the correct way to do this to avoid the unnecessary temporary object construction.

One idea was to change the lambda this way:

[](string &rs,string &arg){ rs+=arg; return rs; }

In this case, I thought I force efficient concatenation of the strings and help the compiler (I know I shouldn't) omit the unnecessary copy, since this should be equivalent to (pseudocode):

accum = [](& accum,& arg){ ...; return accum; }

and thus

accum = & accum;

Another idea was to use

accum = [](& accum,& arg){ ...; return std::move(accum); }

But this would probably lead to something like:

accum = std::move(& accum);

Which looks very suspicious to me.

What is the correct way to write this to minimize the risk of the unnecessary creation of temporary objects? I'm not just interested in std::string, I'd be happy to have a solution, that would probably work for any object that has copy and move constructors/assignments implemented.


Try the following

  [](string &rs, const string &arg) -> string & { return rs+=arg; });

Before this call maybe there is a sence to call

std::string::size_type n = std::accumulate( foo.begin(), foo.end(), 
   std::string::size_type( 0 ),
   [] ( std::string_size_type n, const std::string &s ) { return ( n += s.size() ); } );

res.reserve( n );