分配没有中间对象的操作

时间:2013-11-29 00:37:08

标签: c++

鉴于这样的课程:

class Vec{
  int comp[2];
public:
  void add(Vec& vec, Vec& vec2){
    comp[0] = vec.comp[0] + vec2.comp[0];
    comp[1] = vec.comp[1] + vec2.comp[1];
  }
  Vec operator+ (Vec& vec){
    Vec res;
    res.comp[0] = comp[0] + vec.comp[0];
    res.comp[1] = comp[1] + vec.comp[1];
    return res;
  }
};

有两个成员函数基本上做同样的事情,即将两个Vec加在一起。当然,不同之处在于add函数中没有涉及中间值,而operator+声明了Vec的本地对象。

我的问题是,有没有办法将operator+operator=结合使用,使其具有与add相同的语义,没有中间值?理由是减少所涉及的中间值的数量,以提高效率,同时保持operator语法的优雅。

GMP库的C ++接口显然能够做到这一点:http://gmplib.org/manual/C_002b_002b-Interface-General.html#C_002b_002b-Interface-General

  

该实现的一个重要特征是像a = b + c这样的表达式会导致对相应mpz_add的单次调用,而不会对b + c部分使用临时值。

我想知道是否有可能这样做,或者GMP是否必须使用某种解决方法呢?

3 个答案:

答案 0 :(得分:1)

我认为没有真正的优势,因为你的对象非常小。但是对于像动态分配的大型向量这样的东西,这可能很有用。

实现它的一种方法是创建一个临时的noop类来保存未评估的表达式。此类可以转换为Vec,以便它对用户透明。关键是你现在可以为add表达式创建一个专门的operator =。一些代码(填补空白):

struct VecAdd;
struct Vec
{
    Vec& operator=(const VecAdd& vecadd) { /*...*/ }
};

struct VecAdd
{
    const Vec& v1;
    const Vec& v2;
    operator Vec() { return Vec(/*...*/); } // for things like: f(v+u);
};

VecAdd operator+(const Vec& a, const Vec& b) { return VecAdd{a, b}; }

这就是GMP实际上做的事情。但是有很多宏和模板可以使代码重复性降低。

答案 1 :(得分:1)

这是一个坏主意,因为它违反了大多数人对操作员行为的自然假设。

不幸的是,它也非常重要(特别是像gmpxx这样的库,它们想要使用运算符提供自然代码,高性能,并且有大量对象作为参数)。他们是如何做到这一点的?通过使用表达式模板,他们可以在编译时优化表达式。这个想法是运算符不直接返回值,而是返回表达式类的具体实例,然后可以使用元编程来操作它们。

表达式模板是一个相当高级的主题,您应该相对确定它将为您的代码带来显着的好处。在您的示例中,向量的大小不够相关。

Wiki Expression Templates

答案 2 :(得分:0)

operator+=如何用作myVec += otherVec