Согласно моему пониманию ниже код должен вызывать конструктор перемещения Test
класс, так как эта функция возвращается по значению, которое означает выражение GetTestObj()
должно быть rvalue и xvalues неявно перемещены, но почему этот код вызывает конструктор копирования?
class Test
{
public:
Test()
{
}
Test(const Test& arg)
{
std::cout<<"Copy Constructor Called..."<<std::endl;
}
Test(Test&& arg)
{
std::cout<<"Move Constructor Called..."<<std::endl;
}
};
Test GetMyTestObj()
{
Test *ptr = new Test();
return *ptr;
}
Test dummy = GetMyTestObj(); //Copy Constructor Called...
В вашем коде фактически есть одна копия из *ptr
в возвращаемое значение и один ход от GetMyTestObj()
в dummy
, Тем не менее, компилятор elides движение, так что вы не увидите его след. Если вы пройдете -fno-elide-constructors
в GCC или Clang, то вы должны увидеть копию и ход (демонстрация).
Если вы хотите построить возвращаемое значение для перемещения, вам нужно использовать std::move
:
Test GetMyTestObj()
{
Test *ptr = new Test();
return std::move(*ptr);
}
Однако в этом случае нет необходимости в динамическом размещении; это неэффективно и теряет память с вашей реализацией. Вы должны просто использовать автоматическую переменную:
Test GetMyTestObj()
{
Test test;
//I assume you're doing something else here
return test;
}
С помощью приведенного выше кода компилятор может фактически исключить обе конструкции.
Если вы ничего не делаете в этой функции, вы должны просто построить dummy
непосредственно:
Test dummy{};
значение здесь не копируется (конструктор не вызывается из-за отсутствия копирования):
Test dummy = GetMyTestObj();
но здесь:
return *ptr;
потому что функция должна сделать объект rvalue из ссылки lvalue. В принципе, GetMyTestObj()
Функция в этом случае эквивалентна:
Test *ptr = new Test();
Test returnValue(*ptr);
return returnValue;
что означает выражение
GetTestObj()
должно быть rvalue и xvalues неявно перемещены
Во-первых, ответьте прямо на свой вопрос, GetTestObj()
это prvalue.
- вызов функции или перегруженное выражение оператора не возвращаемого типа, например
str.substr(1, 2)
,str1 + str2
, или жеit++
;
Дело в том, что операция копирования / перемещения необходима для return *ptr;
; ptr
является именованной переменной, которая является именующий. *ptr
Это тоже значение, оно не может быть перемещено.
Вы могли бы использовать std::move
явно, чтобы сделать xvalue подвижным:
return std::move(*ptr);