Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should std::move be used in return-statements for effeciency?

I cannot figure out if the std::move in the following code does anything good or that it is completely wrong? The class Object has both Move and Copy constructor defined.

First: With Move:

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{
    return std::move(Object(*this) *= rhs);  // We end in move constructor
}

Second: Without Move:

template<typename T> template <typename F> 
const Object<T> Object<T>::operator*(const F& rhs) const 
{
    return Object(*this) *= rhs; // We end in copy constructor
}

The *= operator is defined as:

template<typename T> template<typename F>  
Object<T>& Object<T>::operator*=(const F& rhs) 
{
    for(int i = 0; i < dimension ; i++)
    {
        _inner[i] *= rhs;
    }
    return *this;
}

Here is the code i use to test it:

Object<double> test(4);
Object<double> test2(test * 4);
std::cout << test2; // works fine

Result In the first case we end in the move constructor and in the second we end in the copy constructor.

In either case the code compiles.

Is one more efficient than the other since I would assume it is faster to move the new object out instead of copying it out?

Additional info: I use the following compiler: g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3

like image 754
CodeTower Avatar asked May 17 '13 09:05

CodeTower


1 Answers

Is one more efficient than the other since I would assume it is faster to move the new object out instead of copying it out?

Yes, using std::move here will be more efficient, assuming the object has move semantics more efficient than copying.

Usually, when returning a temporary or a local variable, move semantics will be used automatically. However, in this case you're not directly returning the temporary, but rather the lvalue reference returned by operator*=. Since an lvalue won't be moved, you do need std::move in this case to turn it into an rvalue.

However, you should not return a const value, as this prevents the return value from being used to move-initialise (or move-assign to) another object. Your example will initialise test2 by copying the return value, although that copy might be elided.

Alternatively, you could implement it using a local variable:

template<typename T> template <typename F> 
Object<T> Object<T>::operator*(const F& rhs) const 
{
    Object lhs(*this);
    lhs *= rhs;
    return lhs;
}

Not only can the return value be moved, but the move itself can be elided.

like image 199
Mike Seymour Avatar answered Nov 19 '22 21:11

Mike Seymour