2016-05-31 10 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; 
} 

Wenn LL1 = LL2 ausgeführt wird, welcher aufgerufen werden soll.Warum wird der Kopierkonstruktor vor der Kopierzuweisung aufgerufen?

Ich erwarte die Kopie-Zuordnung passieren. Aber der Code wurde in der folgenden Reihenfolge ausgeführt

  1. Copykonstruktor
  2. Copy-Assignemnt
  3. Destructor

Was mache ich falsch? und warum wurde der Destruktor genannt?

+0

Basierend auf std :: swap, ich würde vermuten, die Sie tatsächlich in "sehen möchten Konstruktoren bewegen "und" Zuordnung verschieben ". –

Antwort

1
LinkedList& operator=(LinkedList byValLinkedList); 

Ihre Kopie Konstruktor von Wert seiner Parameter. Das bedeutet, dass

LL1=LL2; 

eine Kopie LL2, um es vorbei Wert zu machen braucht. Das ist, was "nach Wert" bedeutet. Daher der Kopierkonstruktor.

zu tun Kopie Konstruktion zu vermeiden, muss der Zuweisungsoperator seine Parameter als Referenz nehmen, statt:

LinkedList& operator=(const LinkedList &byValLinkedList); 

Das heißt, wenn Sie natürlich den Zuweisungsoperator std::swap nicht ganz umsetzen können. Aber das wäre eine andere Frage ...

Kurz gesagt, Sie haben zwei Möglichkeiten: Entweder implementieren Sie zwei Kopie Konstruktoren, eine, die eine const Referenz und eine, die nicht, mit der letzteren in der Lage ist zu verwenden std::swap. Oder deklarieren Sie _head als mutable.

+0

In Copy-and-Swap möchten Sie nicht vermeiden, den Kopierkonstruktor aufzurufen. Sie möchten, dass beide Kopieroperationen (Kopierzuordnung und Kopierkonstruktion) im Kopierkonstruktor nur einmal implementiert werden. –

0

In Ihrer Zuweisung wird der Operator byVallinkedList nach Wert übergeben. Dieses LinkedList-Objekt wird mit Ihrem Kopierkonstruktor initialisiert.

1

Sie machen nichts falsch, genau so soll Copy-and-Swap funktionieren.

Der Kopierkonstruktor wird aufgerufen, um den Parameter einzurichten, der als Wert übergeben wird. Das ist toll, denn sonst müsste Ihr Kopierzuweisungs-Operator den Code zum Erstellen einer Kopie enthalten. Auf diese Weise können Sie die Logik im Kopierkonstruktor wiederverwenden.

Dann verlässt der Parameter den Gültigkeitsbereich und wird am Ende der Funktion zerstört. Aufgrund des Swap-Aufrufs enthält der Parameter nun die Ressourcen, die zuvor von *this gehalten wurden. Auch sehr wünschenswert, weil der Destruktor sich darum kümmert, sie zu befreien - andernfalls müssten Sie Bereinigungscode für den Kopierzuweisungsoperator schreiben, um die Daten, die durch die Zuweisung ersetzt werden, richtig loszuwerden.

Neben der Wiederverwendung von Code bietet Copy-and-Swap auch Ausnahmesicherheit. Wenn Sie die Kopie direkt in das linke Objekt (*this) kopiert haben, dann haben Sie, wenn etwas schief ging, den alten Wert bereits verloren und können die Dinge nicht unverändert lassen. Aber mit Copy-and-Swap erledigt der Copy-Konstruktor seine Arbeit zuerst - wenn irgendetwas schief geht, wie zum Beispiel, dass der Speicher knapp wird, behält *this seinen vorherigen Wert bei.

Es der Copy-and-Swap-Idiom hier eine sehr ausführliche Erklärung ist: