将移动语义防止复制在这里?

时间:2013-05-14 00:00:05

标签: c++ c++11 move

// --- Move constructor
Matrix(Matrix&& other) throw() : data_(other.data_), Rows_(other.Rows_), Columns_(other.Columns_) { other.Rows_ = other.Columns_ = 0; other.data_ = nullptr; }

// --- Move assignment
Matrix & operator=(Matrix&& other) throw() {
    using std::swap;
    swap(Rows_, other.Rows_);
    swap(Columns_, other.Columns_);
    swap(data_, other.data_); 
    return *this; }

MultiplyAdd实施:

template <class T>
Matrix<T> MultiplyAdd(const T a,const Matrix<T> &x,const T b) {
    Matrix<T> out(a*x+b);
    return out; }

template <class T>
Matrix<T> MultiplyAdd(const Matrix<T> a,const Matrix<T> &x,const T b) {
    Matrix<T> out(a*x+b);
    return out; }

int main(){
    Matrix<> x = // some initialization
    auto&& temp_auto = MultiplyAdd(a,x,b);
    for (int i = 1; i < N-1; i++) {
        temp_auto = MultiplyAdd(temp_auto,temp2,b); }
    return 0;
}

问题: 在最后一个代码段中使用auto关键字会避免创建临时代码吗?之前和'for'循环中更重要。

1 个答案:

答案 0 :(得分:1)

  

在最后一个代码段中使用auto关键字会避免创建临时代码吗?

没有。无论如何都需要创建临时值,因为temp_auto是引用,并且必须存在引用绑定的内容。

如果你做完了,你避免创建临时的几率会更高:

auto temp_auto = MultiplyAdd(a,x,b);

在这种情况下,编译器可以执行复制/移动省略并将MultiplyAdd()的结果直接构造到temp_auto,而无需调用移动构造函数。

我所说的“赔率”的原因是,根据C ++ 11标准的第12.8 / 31段,编译器有权(但没有义务)执行复制/移动省略。

为了澄清发生了什么,我将尝试解释返回对象时编译器必须做什么。考虑这个简单的函数和随后的函数调用:

X foo() { X x; /* ... */ return x; }

// ...

X y = foo();

这里,当返回x时,编译器必须:

  1. x移动构建一个临时文件(让我们称之为t);
  2. y移动构建t
  3. 现在感谢copy elision,允许编译器避免创建临时t,直接在x中构造返回的对象y,并忽略对移动的两个调用构造

    另一方面,在循环内部:

    temp_auto = MultiplyAdd(temp_auto,temp2,b);
    

    您正在进行作业。在我们的简单示例中,这相当于:

    X foo() { X x; /* ... */ return x; }
    
    // ...
    
    X y;
    y = foo();
    

    即使在这里,当从x返回foo()时,编译器必须:

    1. x foo()移动构建一个临时文件(让我们再次称它为t);
    2. t移至y
    3. 即使在这种情况下,也可以通过直接将x(而不是t)传递给分配给y的移动赋值运算符来避免创建临时值,尽管不能省略对移动赋值运算符的调用(只能调用复制/移动构造函数)。

      请注意,在原始示例(其中temp_auto是引用)和上面的修改示例中都是如此,其中temp_auto是类类型的对象。