Следует ли использовать std::move в операторах возврата для повышения эффективности?

Я не могу понять, делает ли std::move в следующем коде что-то хорошее или это совершенно неправильно? В классе Object определены конструкторы Move и Copy.

Во-первых: с перемещением:

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
}

Второй: без перемещения:

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
}

Оператор *= определяется как:

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;
}

Вот код, который я использую для проверки:

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

Результат В первом случае мы заканчиваем конструктор перемещения, а в втором случае заканчиваем конструктор копирования.

В любом случае код компилируется.

Является ли один из них более эффективным, чем другой, поскольку я предполагаю, что быстрее переместить новый объект, чем копировать его?

Дополнительная информация: я использую следующий компилятор: g++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3


person CodeTower    schedule 17.05.2013    source источник
comment
Не возвращайте const значений, не используйте явно std::move локальные/временные переменные, это запрещает (N)RVO. Почему бы не написать operator* как Object tmp(*this); tmp *= rhs; return tmp;? Таким образом, компиляторы видят, что вы возвращаете локальную переменную, и автоматически превращают ее в rvalue при returnинге.   -  person Xeo    schedule 17.05.2013
comment
Взгляните на: stackoverflow.com/questions /4986673/   -  person Steve    schedule 17.05.2013
comment
Я только что протестировал без const, это не меняет ситуацию, но из ответов я понял, что мне нужно std::move, так как я возвращаю lvalue. Если бы с другой стороны было и rvalue мне не нужно было std::move. И, наконец, если бы я использовал временную переменную, она была бы автоматически перемещена?   -  person CodeTower    schedule 17.05.2013


Ответы (1)


Является ли один более эффективным, чем другой, поскольку я предполагаю, что быстрее переместить новый объект, а не копировать его?

Да, использование std::move здесь будет более эффективным, если предположить, что семантика перемещения объекта более эффективна, чем копирование.

Обычно при возврате временной или локальной переменной автоматически используется семантика перемещения. Однако в этом случае вы возвращаете не временное значение напрямую, а ссылку lvalue, возвращенную operator*=. Поскольку lvalue не будет перемещено, в этом случае вам понадобится std::move, чтобы превратить его в rvalue.

Однако вы не должны возвращать значение const, так как это предотвращает использование возвращаемого значения для перемещения-инициализации (или перемещения-назначения) другому объекту. В вашем примере test2 будет инициализировано путем копирования возвращаемого значения, хотя эта копия может быть опущена.

В качестве альтернативы вы можете реализовать его с помощью локальной переменной:

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

Можно не только переместить возвращаемое значение, но и исключить само перемещение.

person Mike Seymour    schedule 17.05.2013
comment
Я подозреваю, что RVO позаботится о случае lvalue, поэтому он должен быть неразличим (возможно, даже с небольшим преимуществом для RVO перед перемещением). Но ваш последний пример (локальная переменная) все равно все решает. +1 - person syam; 17.05.2013
comment
@syam: я совершенно уверен, что исключение разрешено только при (непосредственном) возврате временной или локальной автоматической переменной. Конечно, мой компилятор не исключает копию при возврате lvalue. - person Mike Seymour; 17.05.2013
comment
Также рекомендуется возвращать не-const Object<T>, так как возвращаемое значение вызовет копирование, а не перемещение, если оно используется как auto c = a * b;. - person Xeo; 17.05.2013
comment
@Xeo: Да, я только что заметил const и посоветовал не делать этого. (Я не заметил этого в своих тестах, так как эту копию можно опустить). - person Mike Seymour; 17.05.2013