2
// --- 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”循环之前和更重要的是。

4

1 回答 1

1

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

不,无论如何都需要创建一个临时的,因为temp_auto它是一个引用,并且必须有一些引用绑定到的东西。

如果您这样做了,您避免创建临时文件的几率会更高:

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

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

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

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

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

// ...

X y = foo();

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

  1. x从(我们称之为)移动构造一个临时的t
  2. y从移动构造t

现在由于复制省略,允许编译器避免创建临时的,直接在中t构造返回的对象,并省略对移动构造函数的调用。xy

另一方面,在循环内部:

temp_auto = MultiplyAdd(temp_auto,temp2,b);

你正在做一个任务。在我们的简单示例中,这相当于:

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

// ...

X y;
y = foo();

即使在这里,当从 中返回xfoo(),编译器也必须:

  1. x从from移动构建一个临时的foo()(让我们再次调用它t);
  2. 移动分配ty

即使在这种情况下,也可以通过直接x(而不是t)传递给分配给 的移动赋值运算符来避免创建临时对象y,尽管不能省略对移动赋值运算符的调用(仅调用复制/移动构造函数可以省略)。

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

于 2013-05-14T00:02:10.770 回答