Является ли категория значения функции, возвращаемой по значению, всегда xvalue?

Согласно моему пониманию ниже код должен вызывать конструктор перемещения 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...

0

Решение

В вашем коде фактически есть одна копия из *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{};
2

Другие решения

значение здесь не копируется (конструктор не вызывается из-за отсутствия копирования):

Test dummy = GetMyTestObj();

но здесь:

return *ptr;

потому что функция должна сделать объект rvalue из ссылки lvalue. В принципе, GetMyTestObj() Функция в этом случае эквивалентна:

Test *ptr = new Test();
Test returnValue(*ptr);
return returnValue;
0

что означает выражение GetTestObj() должно быть rvalue и xvalues ​​неявно перемещены

Во-первых, ответьте прямо на свой вопрос, GetTestObj() это prvalue.

  • вызов функции или перегруженное выражение оператора не возвращаемого типа, например str.substr(1, 2), str1 + str2, или же it++;

Дело в том, что операция копирования / перемещения необходима для return *ptr;; ptr является именованной переменной, которая является именующий. *ptr Это тоже значение, оно не может быть перемещено.

Вы могли бы использовать std::move явно, чтобы сделать xvalue подвижным:

return std::move(*ptr);
0
По вопросам рекламы [email protected]