c ++用移动而不是复制累积 [英] c++ accumulate with move instead of copy

查看:29
本文介绍了c ++用移动而不是复制累积的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码

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

我在这里想要的是避免字符串复制.不幸的是,这不是通过 vs2012 实现的累积实现的.内部累加调用另一个函数 _Accumulate 并且右值功能在此过程中丢失.

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.

我改为像这样调用 _Accumulate 函数

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.

是否必须重写 std 库以考虑右值参数?

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?

推荐答案

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

Checking one of the recent post C++11 drafts (N3337.pdf) we can see that the effect of std::accumulate is specified as

通过用初始值 init 初始化累加器 acc 来计算其结果,然后使用 acc = acc + *i 或 acc = binary_op(acc, *i) 修改范围内的每个迭代器 i[第一个,最后一个)按顺序.

Computes its result by initializing the accumulator acc with the initial value init and then modifies it with acc = acc + *i or acc = binary_op(acc, *i) for every iterator i in the range [first,last) in order.

因此,标准实际上禁止使用 std::move 作为旧累加器值的实现,如下所示:

So, the standard actually forbids implementations that use std::move for the old accumulator value like this:

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):自己实施这种移动感知积累.

Option (1): Implement this move-aware accumulate yourself.

选项(2):继续使用类似的函子

Option (2): Keep using a functor like

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+ 重载也有意按值返回.

Note that I did not use rvalue reference return types here. This is intentional since it might avoid dangling reference issues, for example in the case where the last overload is picked and 'a' initialized to refer to a temporary object. All the operator+ overloads for strings also intentionally return by value.

除此之外,您可能希望将 std::copy 与 std::stringstream 和输出流迭代器结合使用.

Apart from that you might want to use std::copy in combination with std::stringstream and an output stream iterator.

附录:替代 mutating_string_adder 与一些部分完美转发:

Addendum: Alternate mutating_string_adder with some partial perfect forwarding:

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

这篇关于c ++用移动而不是复制累积的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆