Reputation:
// --- 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.
Upvotes: 2
Views: 193
Reputation: 126582
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:
x
(let's call it t
);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:
x
from foo()
(let's call it t
again);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.
Upvotes: 1