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

will move semantics prevent copying here?

本文关键字:复制 在这里 移动 语义      更新时间:2023-10-16
// --- 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关键字会避免创建临时文件吗?

在最后的代码片段中使用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. t移出y

现在,由于复制省略,编译器可以避免创建临时t,直接在y中构造返回对象x,并省略对move构造函数的调用。

另一方面,在循环中:

temp_auto = MultiplyAdd(temp_auto,temp2,b);

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

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

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

  1. foo()(让我们再次将其称为t)中移出x的临时对象;
  2. 移动ty .

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

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