2016-05-31 8 views
0
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

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

+0

на основе станд :: своп, я думаю, вы, возможно, на самом деле хотите, чтобы посмотреть в " move constructors "и" move assign ". –

ответ

1
LinkedList& operator=(LinkedList byValLinkedList); 

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

LL1=LL2; 

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

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

LinkedList& operator=(const LinkedList &byValLinkedList); 

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

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

+0

В случае копирования и замены вы не хотите, чтобы вызов вызывал конструктор копирования. Вы хотите, чтобы обе операции копирования (назначение копии и построение копии) выполнялись только один раз, в конструкторе копирования. –

0

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

1

Вы не ошибетесь, это как раз то, как должна работать копия и своп.

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

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

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

Там очень обширное объяснение копирования и обмена идиомы здесь:

Смежные вопросы