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”部分。 from tmp 的初始副本仍将是副本。这是一个经典的 Schlemiel the Painter's algorithm,但比在 C 中使用 strcat 的通常示例还要糟糕。
如果accumulate 只使用+= 而不是+ 和=,那么它会避免所有这些副本。
但 C++11 确实为我们提供了一种更好的方法,同时保持简洁,使用范围 for:
string concat;
for (const string &s : v) { concat += s; }
编辑:我想标准库供应商可以选择实现accumulate,并将操作数移动到+,所以tmp = tmp + "foo" 将变为tmp = move(tmp) + "foo",这几乎可以解决这个问题。我不确定这样的实现是否会严格遵守。 GCC、MSVC 和 LLVM 在 C++11 模式下都不会这样做。由于accumulate 在<numeric> 中定义,人们可能会认为它仅设计用于数字类型。
编辑 2:从 C++20 开始,accumulate 已重新定义为使用 move,就像我之前编辑的建议一样。我仍然认为这是对仅设计用于算术类型的算法的可疑滥用。