vector<string> v(10, "foo");
string concat = accumulate(v.begin(), v.end(), string(""));
这个例子在任何C++标准中都是糟糕的编程。它相当于这个:
string tmp;
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
tmp = tmp + "foo"; //copy tmp, append "foo", then copy the result back into tmp
C++11的移动语义只会处理“将结果复制回tmp”的部分。从tmp中进行的初始复制仍然是复制。这是一个经典的
Schlemiel画家算法,甚至比在C中使用
strcat
的例子更糟糕。
如果
accumulate
只使用
+=
而不是
+
和
=
,那么它就可以避免所有这些复制。
但是,C++11确实为我们提供了一种更好的方法,同时保持简洁,使用范围
for
:
string concat;
for (const string &s : v) { concat += s; }
编辑:我认为标准库供应商可以选择使用move操作符将操作数移到加号上来实现accumulate
,因此tmp = tmp + "foo"
将变成tmp = move(tmp) + "foo"
,这基本上解决了这个问题。我不确定这样的实现是否严格符合规范。在C++11模式下,GCC、MSVC和LLVM都没有这样做。而且由于accumulate
是在<numeric>
中定义的,人们可能会认为它只适用于数字类型。
编辑2:从C++20开始,accumulate
已被重新定义为使用move
,就像我之前编辑中的建议一样。我仍然认为这是对一个只设计用于算术类型的算法的可疑滥用。