Конструктор перемещения должен вызываться по умолчанию - PullRequest
2 голосов
/ 01 августа 2020

В следующем случае, когда я создал ctor перемещения в классе Integer, я ожидаю, что он должен вызываться по умолчанию для ссылки rvalue при создании объекта Product, но я получаю вызов только конструктора копирования. G cc - 7.5.0 в Ubuntu 18

#include<iostream>
using namespace std;

class Integer 
{
    int *dInt = nullptr;
public: 
    Integer(int xInt)  {
        dInt = new int(xInt);
        cout<<"Integer Created"<<endl;
    } 
    Integer(const Integer &xObj)
    {
        cout<<"Copy called"<<endl;
        dInt = new int(xObj.mGetInt());
    }

    Integer(Integer &&xObj)
    {
        cout<<"Move called"<<endl;
        dInt = xObj.dInt;
        xObj.dInt = nullptr;
    }

    Integer& operator=(const Integer &xObj)
    {
        cout<<"Assignment operator called"<<endl;
        *dInt = xObj.mGetInt();
        return *this;
    }

    Integer& operator=(Integer &&xObj)
    {
        cout<<"Move Assignment operator called"<<endl;
        delete dInt;
        dInt = xObj.dInt;
        xObj.dInt = nullptr;
        return *this;   
    }
    ~Integer() 
    {
        cout<<"Integer destroyed"<<endl;
        delete dInt;
    }

    int mGetInt() const {return *dInt;}
};

class Product 
{
    Integer dId;
public: 
    Product(Integer &&xId)
    :dId(xId)
    {

    }
};
int main () 
{
    Product P(10); // Notice implicit conversion of 10 to Integer obj.
}

В приведенном выше случае метод move вызывается, если я использую dId (std :: move (xId)) в классе продукта ctor, я ожидал, что он должен вызвать по умолчанию для ссылки rvalue. В следующем случае я не смог избежать создания временного объекта класса Integer. Есть ли хороший способ избежать создания временного объекта.

    Product(const Integer &xId)
    :dId(xId)
    {

    }
    
    Product(10); // inside main

Моя цель вышеупомянутого вопроса - построить свое понимание, чтобы я мог лучше использовать временную объектную память.

1 Ответ

3 голосов
/ 01 августа 2020

Вам нужно std::move для "распространения" rvalue-reference-ness.

Внутри тела следующей функции:

void foo(int&& x);

… выражение x - это lvalue int. Не int&&.

Ссылки на самом деле «не существуют» - даже если они поддерживаются системой типов, они должны рассматриваться как псевдонимы (а не отдельные объекты), поэтому использование x внутри foo обрабатывается так же, как использование оригинала, упомянутого int внутри foo ... и при этом также создает копию, как вы знаете.

Это выполнит работу:

Product(Integer&& xId)
    : dId(std::move(xId))
{}

Однако я действительно рекомендую вам брать Integer по значению:

Product(Integer xId)
    : dId(std::move(xId))
{}

Таким образом, вы можете использовать тот же конструктор для передачи lvalue Integer тоже, и будет создана копия , если необходимо , тогда как перемещение произойдет автоматически, если нет (например, путем передачи литерала, который автоматически инициирует выбор Integer) конструктор перемещения).

...