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 the Painter 算法,但比strcat
C 中使用的通常示例还要糟糕。
如果accumulate
只是使用+=
而不是,+
那么=
它将避免所有这些副本。
但是 C++11 确实为我们提供了一种更好的方法,同时保持简洁,使用 range 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++20accumulate
开始,已重新定义为move
按照我之前编辑的建议使用。我仍然认为这是对仅设计用于算术类型的算法的可疑滥用。