2016-07-14 17 views
-1
#include <iostream> 
#include <memory> 

using namespace std; 


class Node 
{ 

//Private variables. 
private: 
    std::unique_ptr<Node> next; //Next node. 
    std::unique_ptr<Node> prev; //Previous node. 


    //Int value. 
    int value; 



//Public variables. 
public: 

    //Constructor. 
    Node(int v) 
    :next(nullptr), prev(nullptr), value(v) 
    { 
    } 


    //Set next node. 
    void set_next(std::unique_ptr<Node> new_node) 
    { 
     next = std::move(new_node); 
    } 


    //Set previous node. 
    void set_prev(std::unique_ptr<Node> new_node) 
    { 
     prev = std::move(new_node); 
    } 


    //Set value. 
    void set_value(int v) 
    { 
     value = v; 
    } 


    //Get next node. 
    std::unique_ptr<Node> get_next() 
    { 
     return std::move(next); 
    } 


    //Get previous node. 
    std::unique_ptr<Node> get_prev() 
    { 
     return std::move(prev); 
    } 


    //Get value. 
    int get_value() 
    { 
     return value; 
    } 



}; 


class LinkedList 
{ 

//Private variables. 
private: 
    std::unique_ptr<Node> head; 
    std::unique_ptr<Node> tail; 



//Public variables. 
public: 

    //Constructor. 
    LinkedList() 
    :head(nullptr), tail(nullptr) 
    { 
    } 


    //Append a item to the list. 
    void append(int v) 
    { 

     //Creating a new node. 
     std::unique_ptr<Node> new_node(new Node(v)); 


     //If this is the very first node. 
     if (head == nullptr || tail == nullptr) 
      { 
       head = std::move(new_node); 
       tail = std::move(new_node); 
      } 



     //Append. 
     else 
      { 
       tail -> set_next(std::move(new_node)); //Linking the new node. 
       new_node -> set_prev(std::move(tail)); //Set the previous. 
       tail = std::move(new_node);    //Update the tail. 
      } 

    } 


    //Print all the elements. 
    void print() 
    { 

     //Starting node. 
     std::unique_ptr<Node>curr = std::move(head); 


     //While Loop. 
     while(curr != nullptr) 
      { 
       cout << curr -> get_value() << endl; 
       curr = std::move(curr -> get_next()); 
      } 
    } 

}; 


int main() 
{ 
LinkedList myList; 

myList.append(1); 
myList.append(2); 
myList.append(3); 
myList.append(4); 

myList.print(); 

return 0; 
} 

Ich sollte für Ausgabe 1,2,3,4 sehen, aber stattdessen sehe ich nur 4! Ich habe das Debuggen und ich fand heraus, die folgende Anweisung läuft 4mal:C++ - verknüpfte Liste wird nicht ausgeführt, wie ich erwartet habe (Smart Pointer)

  //If this is the very first node. 
     if (head == nullptr || tail == nullptr) 
      { 
       head = std::move(new_node); 
       tail = std::move(new_node); 
      } 

Aber warum 4-mal ausgeführt wird? Das erste Mal, Kopf und Schwanz wird null sein, aber danach werden sie irgendwo Punkt so diese Aussage sollte nie laufen wieder.

Ich bin neu mit Smart-Pointer so denke ich, gibt es, wo ich fehlt.

+6

Mehrere einzigartigen Zeiger können nicht auf das gleiche Objekt zeigen und einmal einen einzigartigen Zeiger auf einem anderen einzigartigen Zeiger, das Original nicht mehr auf das Objekt verschoben. – evan

+0

Schritt durch den Code in einem Debugger, und untersuchen Sie die Zeiger wie Sie sie bewegen, um zu sehen, dass sie Ihre Erwartungen nicht übereinstimmen. – evan

+0

Beantworten einer kurzen Frage in einem Kommentar zu einer gelöschten Antwort: Soll ich solche Datenstrukturen in C++ erstellen? Antwort 1: Selten. Die Standardbibliothek enthält bereits eine Listenstruktur, die fast genau dies tut. Warum erfinden Sie das Rad neu? Antwort 2: Ich würde es ein bisschen anders machen. Wenn Sie 'Node' in' LinkedList' zu einer privaten Klasse machen und diese niemals den Benutzern zugänglich machen, können Sie sich viel Mühe sparen, die Sie dem Schutz von 'node' gewidmet haben. Empfehlen http://stackoverflow.com/questions/38234616/linked-list-private-pointers-c/38235373#38235373 – user4581301

Antwort

3

Eine grundlegende Eigenschaft eines std::unique_ptr ist, dass nur ein std::unique_ptr einen gegebenen Zeiger zur gleichen Zeit besitzen kann. Dies ist genau das, worum es beim "einzigartigen" Teil geht.

std::unique_ptr<Node> new_node(new Node(v)); 

Ok. So weit, ist es gut.

head = std::move(new_node); 
    tail = std::move(new_node); 

Und das ist dein Problem. Sie versuchen, dieselbe std::unique_ptr in zwei andere zu verschieben. Das wird nicht funktionieren. Nur einer von ihnen kann einen Zeiger besitzen.

Ersetzen Sie alle Ihre std::unique_ptr s durch std::shared_ptr s.

+1

eine leichte zwicken: Mehr hier erwähnenswert, dass 'std :: shared_ptr' die Notwendigkeit' std beseitigt :: bewegen. – user4581301

+0

Ok Problem gelöst. Ich möchte auch fragen: Soll ich meine Datenstrukturen in C++ mit Smart Pointers erstellen? In c behandelte ich den Speicher mit den Funktionen free() und malloc(). In C++ fand ich einige Posts, die sagen, dass es nicht gut ist, das "new" -Schlüsselwort zu verwenden, um neue Objekte in Zeigern zu speichern und sie dann aufgrund von Ausnahmeproblemen zu löschen. – babaliaris

+1

@babaliaris in C++ nur in seltenen Fällen "malloc" und "free" verwenden. Verwenden Sie stattdessen "new" und "delete", da sie Konstruktoren und Destruktoren beherrschen. Kann die Verwendung von 'new' und' delete' zu ​​Problemen führen? Darauf kannst du wetten! Vermeiden Sie wo möglich, aber ... Eine verknüpfte Liste ist kein Ort, an dem Sie sie bequem vermeiden können. Der Punkt, an dem Schüler eine verknüpfte Liste schreiben, besteht darin, sie dazu zu bringen, zu lernen, Zeiger richtig und sorgfältig zu verwenden. Ein geteilter Zeiger ist hier nicht die richtige Wahl. Shared Pointer ist, wenn Sie mehrere konkurrierende Besitzer eines Objekts haben. Hier ist die verknüpfte Liste der Eigentümer. – user4581301