Почему конструктор копирования вызывается перед назначением копирования?

class LinkedList
{
public:
    LinkedList() : _head(nullptr) {}
    LinkedList(ListElement *newElement) : _head(newElement) {}
    ~LinkedList() {  };
    LinkedList(const LinkedList& LL);
    LinkedList& operator=(LinkedList byValLinkedList);
private:
    ListElement *_head;
}
LinkedList::LinkedList(const LinkedList & LL)
{
    ListElement *curr = LL._head;

    // If Linked List is empty
    if (isEmpty() && curr != nullptr) {
        _head = new ListElement(curr->getValue());
        curr = curr->getNext();
    }

    ListElement *newNode = nullptr;
    while (curr) {
        newNode = new ListElement(curr->getValue());
        curr = curr->getNext();
    }
}

LinkedList& LinkedList::operator=(LinkedList byValLinkedList)
{

std::swap(_head, byValLinkedList._head);
return *this;
}


int main() {
    using namespace std;
    LinkedList LL1(new ListElement(7));
    //..... some insertions
    LinkedList LL2(new ListElement(5));
    //..... some insertions
    LL1 = LL2;  // What is the order ?
    // ..... do something else
    return 0;
}

Когда LL1 = LL2 выполняется, какой из них должен быть вызван.

Я ожидаю, что назначение копирования произойдет. Но код был выполнен в следующем порядке

  1. Копировать конструктор
  2. Copy-Assignemnt
  3. Destructor

Что я делаю неправильно? и почему был назван деструктор?

3 ответа

Решение
 LinkedList& operator=(LinkedList byValLinkedList);

Ваш конструктор копирования принимает его параметр по значению. Это означает, что

 LL1=LL2;

необходимо сделать копию LL2, чтобы передать его по значению. Вот что означает "передача по значению". Следовательно, конструктор копирования.

Чтобы избежать создания копирования, оператор присваивания должен взять свой параметр по ссылке, вместо этого:

 LinkedList& operator=(const LinkedList &byValLinkedList);

Это означает, что если, конечно, вы не можете реализовать оператор присваивания, используя std::swap, Но это был бы другой вопрос...

Вкратце, у вас есть два варианта: либо реализовать два конструктора копирования, один из которых принимает const ссылка и тот, который не, с последним в состоянии использовать std::swap, Или объявить _head быть mutable,

Вы не делаете ничего плохого, именно так должно работать копирование и обмен.

Конструктор копирования вызывается для установки параметра, который передается по значению. Это здорово, потому что в противном случае ваш оператор копирования должен был бы содержать код для создания копии. Таким образом, вы можете повторно использовать логику в конструкторе копирования.

Затем параметр выходит из области видимости и уничтожается в конце функции. Из-за вызова подкачки параметр теперь содержит ресурсы, которые раньше удерживались *this, Также очень желательно, потому что деструктор позаботится об их освобождении - в противном случае вам придется написать код очистки для оператора присваивания копии, чтобы правильно избавиться от данных, которые заменяются присваиванием.

В дополнение к повторному использованию кода, копирование и замена дает вам исключительную безопасность. Если вы сделали копию прямо в левый объект (*this), то если что-то пошло не так, вы уже потеряли старое значение и не можете оставить все без изменений. Но используя функцию копирования и замены, конструктор копирования сначала выполняет свою работу - если что-то пойдет не так, как, например, нехватка памяти, *this сохраняет свое прежнее значение.

Здесь есть очень подробное объяснение идиомы копирования и обмена:

В вашем операторе присваивания byVallinkedList передается по значению. Этот объект LinkedList инициализируется с помощью вашего конструктора копирования

Другие вопросы по тегам