Цитирование из http://eel.is/c++draft/class.copy.elision:
В следующих контекстах инициализации копирования вместо операции копирования может использоваться операция перемещения:
(3.1) Если выражение в операторе возврата ([stmt.return]) является (возможно, в скобках) id-выражением, которое присваивает объекту имя с автоматическим продолжительность хранения , объявленная в теле или в параметре-объявлении самой внутренней функции, или лямбда-выражения, или
(3.2), если операндом выражения throw является имя энергонезависимого автоматического объекта (кроме параметра функции или catch-предложения), область которого не выходит за пределы самого внутреннего включающего блока try (если есть)
Разрешение перегрузки для выбора конструктора для копии сначала выполняется так, как если бы объект был обозначен как значение .
Следовательно, если вы возвращаете автоматическую (локальную) переменную:
vector<int> ident() {
vector<int> v;
return v;
};
тогда v
будет в операторе return
, обработанном как rvalue , и поэтому возвращаемое значение будет инициализировано как конструктор перемещения.
Однако эти критерии не соблюдаются в вашем коде, поскольку v
в вашем ident
не является автоматической переменной. Следовательно, он рассматривается как lvalue в операторе return
, и возвращаемое значение инициализируется конструктором копирования из вектора, на который ссылается параметр функции.
Эти правила вполне естественны. Представьте, что компиляторам было разрешено переходить со всех значений l в return
операторах. К счастью, они могут, только если они знают, что это lvalue будет уничтожено, что верно для автоматических переменных и параметров, передаваемых значениями в контексте операторов return
.