Ответ 1
DataType data() && { return std::move(values); } // why DataType?
auto values = makeWidget().data();
Временное значение, которое содержит возвращаемое значение, будет инициализироваться с помощью конструктора move, инициализированного с помощью move(values)
.
Затем это временное инициализирует values
, но поскольку makeWidget().data()
является rvalue (то есть, чтобы быть точным), конструктор move вызывается снова - с временным аргументом.
Теперь рассмотрим copy-elision:
Когда безымянный временный, не привязанный к каким-либо ссылкам, будет перемещен или скопированы в объект того же CV-неквалифицированного типа, copy/move опущен. Когда это временное построено, оно построенный непосредственно в хранилище, где он был бы перемещен или скопированы. Когда безымянный временный является аргументом возврата оператор, этот вариант копирования является известным как RVO, "возвращаемое значение оптимизация".
Итак, второе движение (предположительно) будет полностью устранено, и останется только один - тот, который у нас был бы в любом случае, если тип возврата был ссылкой на rvalue.
Проблема с возвратом ссылки rvalue заключается в том, что если мы пишем
auto&& values = makeWidget().data();
values
будет болтаться, поскольку привязка значения x к ссылке не продлевает время жизни anythings. Когда мы возвращаем тип объекта, время жизни увеличивается.