Взаимодействие между идиомой копирования и замены и операциями перемещения - PullRequest
0 голосов
/ 11 февраля 2020

Я пытаюсь создать программу, которая реализует взаимодействие между «копировать и менять» идиому и и move control operations, поэтому я написал этот код:

class PInt
{
public:
    PInt(int = 0);
    PInt(const PInt&);
    PInt(PInt&&) noexcept;
    PInt& operator=(PInt);
    ~PInt();

    int* getPtr()const;

private:
    int* ptr;
    friend void swap(PInt&, PInt&);
};

PInt::PInt(int x) : 
    ptr(new int(x))
{
    std::cout << "ctor\n";
}

PInt::PInt(const PInt& rhs) :
    ptr(new int(rhs.ptr ? *rhs.ptr : 0))
{
    std::cout << "copy-ctor\n";
}

PInt::PInt(PInt&& rhs) noexcept :
    ptr(rhs.ptr)
{
    std::cout << "move-ctor\n";
    rhs.ptr = nullptr; // putting rhs in a valid state
}


PInt& PInt::operator=(PInt rhs)
{
    std::cout << "copy-assignment operator\n";
    swap(*this, rhs);
    return *this;
}

PInt::~PInt()
{
    std::cout << "dtor\n";
    delete ptr;
}

void swap(PInt& lhs, PInt& rhs)
{
    std::cout << "swap(PInt&, PInt&\n";
    using std::swap;
    swap(lhs.ptr, rhs.ptr);
}

PInt gen_PInt(int x)
{
    return {x};
}

int main()
{
    PInt pi1(1), pi2(2);
    //pi1 = pi2; // 1
    //pi1 = PInt{}; // 2
    //pi1 = std::move(pi2); // 3
    pi1 = std::move(PInt{}); // 4


}
  • Все есть Хорошо для меня, поэтому я думаю, что в 1 copy-ctor вызывается оператором copy-asignment для инициализации его параметра (он принимает значение), а затем использует swap. в "2" я присваиваю из r-значения, таким образом, я думаю, что компилятор применяет некоторую оптимизацию "Copy-elision"; создание непосредственно объекта в операторе копирования-копирования.

  • В чем я не уверен, так это 3 и 4. Итак, вот результат 3 и 4:

    строка без комментариев 3:

    ctor
    ctor
    move - ctor
    copy - assignment operator
    swap(PInt&, PInt &
    dtor
    dtor
    dtor
    

строка без комментариев 4:

    ctor
    ctor
    ctor
    move - ctor
    copy - assignment operator
    swap(PInt&, PInt &
    dtor
    dtor
    dtor
    dtor
  • Почему 3 и 4 используют std::move, но для получает n дополнительный конструктор с именем?

** Что эффективно: определение оператора копирования / перемещения-присваивания, принимаемого по значению или двух отдельных версий: назначение копирования и назначение перемещения? Поскольку одна версия каждый раз вызывала ее, она вызывает (дополнительный вызов) copy-ctor или move-ctor для инициализации своего параметра?

1 Ответ

4 голосов
/ 11 февраля 2020

Почему 3 и 4 используют std :: move, но for получает n дополнительный конструктор с именем?

Конструктор "extra" (move) для 3 и 4 предназначен для создания объекта, который аргумент здесь:

PInt& PInt::operator=(PInt rhs)
                      ^^^^^^^^

«дополнительный» конструктор для 4 предназначен для создания этого временного:

pi1 = std::move(PInt{}); // 4
                ^^^^^^
...