Ответ 1
-
Функции не возвращают значения rvalues или lvalues. Категории значений применяются к выражениям. Таким образом, выражение, которое вызывает функцию, может быть значением rvalue или lvalue. В этом случае выражение
getName()
является выражением rvalue, потому что функцияgetName
возвращает объект по значению. Это происходит из п. 5.2.2/10:Вызов функции - это значение lvalue, если тип результата является ссылочным типом lvalue или ссылкой на тип функции, значение xvalue, если тип результата является ссылкой rvalue для типа объекта, и значение pr в противном случае.
Тип результата ваших функций не является ссылкой lvalue или rvalue, поэтому вызов функции является значением prvalue. выражения prvalue являются подмножеством выражений rvalue.
-
Будет использоваться конструктор перемещения (если только оно не будет отменено, каким оно может быть). Это потому, что
getName()
является rvalue, поэтому конструкторstd::string
, который принимает ссылку rvalue, будет лучше соответствовать аргументу. Обратите внимание, что даже если конструкция перемещения отменена, конструктор перемещения должен быть доступен. То есть, код должен быть скомпилирован, даже если он не удалился. -
В целом, оптимизация копирования или перемещения elision полностью избавится от любого копирования или перемещения. Так что, конечно, это быстрее, чем на самом деле. Если движение отменяется, буквально ничего не происходит. Для этого не будет никакого кода. Компилятор достигает этого, напрямую конструируя объект в том месте, где он будет скопирован или перенесен.
Стоит отметить, что это также можно было бы оптимизировать одинаково:
string getName () {
std::string str("meme");
return str;
}
string name = getName();
Здесь пройдут два шага (включая то, что обычно называют Именованная оптимизация возвращаемого значения). Здесь есть два момента. Во-первых, return str;
соответствует критериям для копирования/перемещения elision (§12.8/31):
Это разрешение операций копирования/перемещения, называемое копированием, разрешено в следующих случаях (которые могут быть объединены для устранения нескольких копий):
- в возвращаемом выражении в функции с типом возвращаемого класса, когда выражение является именем энергонезависимого автоматического объекта (кроме функции или параметра catch-clause) с тем же cv-неквалифицированным типом, что и функция возвращаемый тип, операцию копирования/перемещения можно опустить, построив автоматический объект непосредственно в возвращаемое значение функций
- ...
Во-вторых, хотя str
является lvalue, он все равно будет перемещен из-за того, что он соответствует специальному случаю, заданному стандартом (§12.8/32):
Когда критерии для выполнения операции копирования выполняются или выполняются, за исключением того факта, что исходный объект является параметром функции, а подлежащий копированию объект определяется значением lvalue, разрешением перегрузки, чтобы выбрать конструктор для копия сначала выполняется так, как если бы объект был обозначен rvalue.