简体   繁体   English

将移动语义阻止在此处复制吗?

[英]will move semantics prevent copying here?

// --- 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 implementation: 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;
}

Question: Will the use of the auto keyword in the last code snippet avoid the creation of temporaries? 问题:在最后一个代码片段中使用auto关键字可以避免创建临时对象吗? Before and more important inside the 'for' loop. 在“ for”循环内更重要。

Will the use of the auto keyword in the last code snippet avoid the creation of temporaries? 在最后一个代码片段中使用auto关键字会避免创建临时文件吗?

No. A temporary needs to be created anyway, since temp_auto is a reference, and there must be something that reference is bound to. 不会。无论如何,都需要创建一个临时文件,因为temp_auto是一个引用,并且必须绑定了一些引用。

Your odds to avoid the creation of a temporary would be higher if you had done: 如果您这样做,则避免创建临时文件的几率会更高:

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

In which case the compiler could perform copy/move elision and construct the result of MultiplyAdd() directly into temp_auto , without having to call the move constructor. 在这种情况下,编译器可以执行复制/移动temp_autotemp_auto MultiplyAdd()的结果直接构造到temp_auto ,而无需调用move构造函数。

The reason I am talking about "odds" is that per paragraph 12.8/31 of the C++11 Standard, the compiler is entitled, but not obliged, to perform copy/move elision. 我谈论“奇数”的原因是,根据C ++ 11标准的第12.8 / 31段,编译器有权执行复制/移动省略,但没有义务。

To clarify what is going on, I will try to explain what the compiler has to do when returning an object. 为了阐明正在发生的事情,我将尝试解释编译器在返回对象时必须执行的操作。 Consider this simple function and the subsequent function call: 考虑这个简单的函数以及随后的函数调用:

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

// ...

X y = foo();

Here, when returning x , the compiler would have to: 在这里,返回x ,编译器将必须:

  1. Move-construct a temporary from x (let's call it t ); x移动构造一个临时对象(我们称其为t );
  2. Move-construct y from t . t移动构造y

Now thanks to copy elision, the compiler is allowed to avoid the creation of the temporary t , construct the returned object x directly in y , and elide both calls to the move constructor. 现在,由于有了复制省略功能,编译器可以避免创建临时t ,直接在y构造返回的对象x ,并将两个调用都移到move构造函数中。

On the other hand, inside the loop: 另一方面,在循环内:

temp_auto = MultiplyAdd(temp_auto,temp2,b);

You are doing an assignment . 您正在做作业 In our simple example, this is the equivalent of: 在我们的简单示例中,这等效于:

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

// ...

X y;
y = foo();

Even here, when returning x from foo() , the compiler has to: 即使在这里,当从foo()返回x时,编译器也必须:

  1. Move-construct a temporary from x from foo() (let's call it t again); foo() x移动构造一个临时对象(让我们再次将其称为t );
  2. Move-assign t to y . t分配给y

Even in this case, the creation of a temporary can be avoided by passing directly x (instead of t ) to the move-assignment operator that assigns to y , although the call to the move-assignment operator cannot be elided (only calls to copy/move constructors can be elided). 即使在这种情况下,也可以通过将x (而不是t )直接传递给分配给y的移动赋值运算符来避免创建临时项,尽管不能忽略对移动赋值运算符的调用(仅调用copy / move 构造函数可以省略)。

Notice, that this is true both in your original example (where temp_auto is a reference) and in my modified example above, where temp_auto is an object of class type. 注意,在您的原始示例(其中temp_auto是引用)和我上面的修改示例中, temp_auto是类类型的对象,这都是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM