我有以下代码
auto adder = [](string& s1, const string& s2)->string&&
{
if (!s1.empty())
s1 += " ";
s1 += s2;
return move(s1);
};
string test;
test.reserve(wordArray.size() * 10);
string words = accumulate(wordArray.begin(), wordArray.end(),
move(test), adder);
Run Code Online (Sandbox Code Playgroud)
我想在这里避免字符串复制.不幸的是,这并没有通过vs2012的accumulate实现来实现.内部累积调用另一个函数_Accumulate并且rvalue功能在此过程中丢失.
我改为调用_Accumulate函数
string words = _Accumulate(wordArray.begin(), wordArray.end(),
move(test), adder);
Run Code Online (Sandbox Code Playgroud)
我获得了预期的性能提升.
是否必须重写std库以考虑rvalue参数?
还有其他方法我可以使用积累来完成我想要的而不会作弊太多吗?
检查最近的一份 C++11 草案 (N3337.pdf),我们可以看到 std::accumulate 的效果被指定为
通过使用初始值 init 初始化累加器 acc 来计算其结果,然后按顺序对 [first,last) 范围内的每个迭代器 i 使用 acc = acc + *i 或 acc = binary_op(acc, *i) 修改它。
因此,该标准实际上禁止使用 std::move 作为旧累加器值的实现,如下所示:
template <class InputIterator, class T, class BinOp>
T accumulate (InputIterator first, InputIterator last, T init, BinOp binop)
{
while (first!=last) {
init = binop(std::move(init), *first);
++first;
}
return init;
}
Run Code Online (Sandbox Code Playgroud)
这对你来说很不幸。
选项(1):自己实现这个移动感知积累。
选项(2):继续使用函子,例如
struct mutating_string_adder {
string operator()(string const& a, string const& b) const {return a+b;}
string operator()(string & a, string const& b) const {a += b; return std::move(a);}
string operator()(string && a, string const& b) const {a += b; return std::move(a);}
};
Run Code Online (Sandbox Code Playgroud)
请注意,我在这里没有使用右值引用返回类型。这是有意为之,因为它可能会避免悬空引用问题,例如在选择最后一个重载并初始化“a”以引用临时对象的情况下。字符串的所有运算符+重载也有意按值返回。
除此之外,您可能希望将 std::copy 与 std::stringstream 和输出流迭代器结合使用。
附录:mutating_string_adder与部分完美转发交替使用:
struct mutating_string_adder {
template<class T, class U>
std::string operator()(T && a, U && b) const {
return std::move(a) + std::forward<U>(b);
}
};
Run Code Online (Sandbox Code Playgroud)