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 implementation:

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? Before and more important inside the 'for' loop.

  • Use [`noexcept`](http://en.cppreference.com/w/cpp/language/noexcept_spec) instead of `throw()`. – David G May 14 '13 at 00:13
  • @gumtree: Dynamic exception specifications are deprecated in C++11 – Andy Prowl May 14 '13 at 00:15
  • `throw` checks during runtime. `noexcept` at compile time (`throw` is also deprecated). Other reasons -- http://stackoverflow.com/questions/12833241/difference-between-c03-throw-specifier-c11-noexcept – David G May 14 '13 at 00:16
  • @0x499602D2 According to the second answer in the link you've provided, your second statement is not true. [except.spec]/11 – dyp May 14 '13 at 00:32

1 Answers1

1

Will the use of the auto keyword in the last code snippet avoid the creation of temporaries?

No. A temporary needs to be created anyway, since temp_auto is a reference, and there must be something that reference is bound to.

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.

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.

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:

  1. Move-construct a temporary from x (let's call it t);
  2. Move-construct y from t.

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.

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:

  1. Move-construct a temporary from x from foo() (let's call it t again);
  2. Move-assign t to 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).

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.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • odds? so will be temporary avoided or not then? –  May 14 '13 at 00:04
  • @gumtree: Copy/move elision is at the compiler's discretion. In practice, with aggressive optimization the chances that the compiler will decide to elide are very very high. But in principle, it is completely up to the compiler, even if your move constructor has side effects. – Andy Prowl May 14 '13 at 00:05
  • "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." you mean here what is happening within "for loop"? –  May 14 '13 at 00:10
  • @gumtree: Sorry, no, only outside the loop – Andy Prowl May 14 '13 at 00:11
  • @gumtree: I'm sorry, I misread the code. No, what I'm talking about in the answer is the reference binding that happens *before* the loop. The second one will perform a move assignment – Andy Prowl May 14 '13 at 00:12
  • what about inside? it is main source of questions. that's why move constructor is there –  May 14 '13 at 00:12
  • @gumtree: There would be no elision inside the loop, just a call to the move assignment operator. – Andy Prowl May 14 '13 at 00:13
  • @gumtree: I will expand the answer, give me some time. Explaining in comments is more complicated – Andy Prowl May 14 '13 at 00:18
  • @gumtree: I had to edit again, the answer was inaccurate. I apologize for that – Andy Prowl May 14 '13 at 00:33