12

I have the following code

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);

What I would like here is to avoid string copying. Unfortunately this is not accomplished by the vs2012 implementation of accumulate. Internally accumulate calls another function _Accumulate and the rvalue functionality gets lost in the process.

It I instead call the _Accumulate function like so

string words = _Accumulate(wordArray.begin(), wordArray.end(), 
    move(test), adder);

I get the intended performance gain.

Must the std library be rewritten to take rvalue arguments into consideration?

Is there some other way I may use accumulate to accomplish what I want without cheating too much?

4

1 回答 1

4

检查最近发布的 C++11 草案之一(N3337.pdf)我们可以看到 std::accumulate 的效果被指定为

通过使用初始值 init 初始化累加器 acc 来计算其结果,然后按顺序使用 acc = acc + *i 或 acc = binary_op(acc, *i) 为范围 [first,last) 中的每个迭代器 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;
}

这对你来说是不幸的。

选项(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);}
};

请注意,我在这里没有使用右值引用返回类型。这是有意的,因为它可能会避免悬空引用问题,例如在拾取最后一个重载并将“a”初始化为引用临时对象的情况下。字符串的所有 operator+ 重载也有意按值返回。

除此之外,您可能希望将 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);
  }
};
于 2012-12-06T09:50:52.773 回答