2015-05-05 4 views
8

я следующий классRValue ссылки без станд :: двигаться

class widget { 
// The methods only print their name, i.e. c'tor, destructor etc. 
public: 
    widget(); 
    widget(const widget&); 
    widget(widget&&); 
    ~widget(); 
    auto operator=(const widget&) -> widget&; 
    auto operator=(widget&&) -> widget&; 
}; 

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

#include "widget.h" 

auto main() -> int { 

    widget c(std::move(widget())); 
    c = std::move(widget()); 

    return 0; 
}; 

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

Второй вызов делает то же самое, ожидание вызова оператора присваивания перемещения вместо конструктора перемещения. Оставляя основной метод, деструктор вызывается на c.


Сейчас идет интересная часть:

#include "widget.h" 

auto main() -> int { 

    widget c((widget())); 
    c = widget(); 

    return 0; 
}; 

Если я выхожу из вызов std::move, первый случай перестает работать и приводит только один конструктор вызова. В то время как второй случай все еще работает по-прежнему.

Что мне здесь не хватает? Почему эти два вызова функций обрабатывают их параметры по-разному? Я пробовал это на gcc и clang.

+0

'(widghet())' является prvalue, то есть значением r, поэтому он перемещается (если возможно). 'std :: move' не перемещается, он просто меняет категорию значений выражения. Если бы это выражение имело соответствующую категорию значений, это излишне. – Columbo

+1

Скобки необходимы, иначе выражение вычисляется как указатель на функцию, которая не принимает параметров и возвращает «виджет». – mike

+2

Может быть, ваш компилятор оптимизирует некоторые конструкции и копии для вас? –

ответ

12

widget() является чистым Rvalue (prvalue), так что в строке

widget c((widget())); // use widget c{widget()} or c{widget{}} for more clear code 

он будет перемещен. Однако компилятор просто выполняет copy/move elision. Скомпилируйте с помощью -fno-elide-constructors, и вы увидите призывы к конструкторам перемещения во всей их славе.

Всякий раз, когда вы явно используете std::move для перемещения prvalue, вы не позволяете компилятору выполнять эликсирование; поэтому вы видите конструктор перемещения в действии в первом фрагменте. Вот почему почти всегда сложно попытаться «помочь» компилятору, используя std::move в качестве возврата (если вы действительно не хотите возвращать ссылку на rvalue).

+2

Да, нужны дополнительные парнеры. В противном случае это объявление функции, а не определение объекта. –

+0

@BenjaminLindley, ты прав, я его отредактировал. По какой-то причине я ошибочно считал, что «виджет» - это объект, а не имя класса. – vsoftco

Смежные вопросы