2016-10-19 1 views
0

Ich versuche herauszufinden, warum ich einen Seg-Fehler von meiner einfach verknüpften Liste-Implementierung bekomme.Einfach verknüpfte Liste - Segmentierungsfehler aufgrund Destructor-Implementierung

Ich erstelle ein Objekt des Typs Deque namens dq1, Compiler ruft den Destruktor dafür, da das Programm fertig ist - Destruktor ruft remove_front() auf, die mit einigen move() für den Kopf beschäftigt ist. Ich glaube, hier liegt das Problem, aber ich kann nicht herausfinden, wo genau es ist.

Debugger Info - Sie wissen nicht, was Sie davon halten sollen?

#0 0x4013ea std::unique_ptr<Node, std::default_delete<Node> >::get(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:305) 
#1 0x401586 std::unique_ptr<Node, std::default_delete<Node> >::operator bool(this=0x8) (/usr/include/c++/6/bits/unique_ptr.h:319) 
#2 0x40140b std::operator!=<Node, std::default_delete<Node> >(std::unique_ptr<Node, std::default_delete<Node> > const&, decltype(nullptr))(__x=<error reading variable: Cannot access memory at address 0x8>) (/usr/include/c++/6/bits/unique_ptr.h:670) 
#3 0x401132 Deque::size(this=0x7fffffffe520) (Deque.cpp:75) 
#4 0x4010f2 Deque::empty(this=0x7fffffffe520) (Deque.cpp:66) 
#5 0x4016dd main() (/test.cpp:12) 

Deque.cpp

#include "Deque.h" 
#include <iostream> 
#include <memory> 
#include <utility> 
#include <stdexcept> 

using std::cout; 
using std::endl; 
using std::move; 

Deque::~Deque() 
{ 
    while (!empty()) remove_front(); 
} 


void Deque::insert_front(int a) 
{ 
    std::unique_ptr<Node> new_node; 
    new_node->val = move(a); 
    new_node->next = move(head); // head is wiped. 
    head = move(new_node); //head is init. with new_node val*/ 
} 


int Deque::remove_front() 
{ 
    if (empty()) {throw std::runtime_error(std::string("Empty"));}; 

    std::unique_ptr<Node> old; 
    int return_value = head->val; 
    old = move(head); 
    head = move(old->next); 
    delete &old; 
    return return_value; 
} 


bool Deque::empty() const 
{ 
return (size() == 0); 
} 
int Deque::size() const 
{ 

int size_val = 0; 
const Node* p = head.get(); 

while (p != NULL) 
    { 
     size_val++; 
     p = p->next.get(); 
    } 
    return size_val; 
} 

test.cpp

#include <iostream> 
#include "Deque.h" 



using std::cout; 
using std::endl; 

int main() 
{ 

    Deque dq1; 
     return 0; 
} 

deque.h

#include "Node.h" 
#include <memory> 

class Deque{ 
    public: 
     Deque() = default; 
     Deque(const Deque&); 
     ~Deque(); //must use constant space 
     Deque& operator=(const Deque&){return *this;}; 
     void insert_front(int); 
     int remove_front(); 
     bool empty() const; 

    private: 
    friend Node; 
     std::unique_ptr<Node> head ; 
     std::unique_ptr<Node> tail ; 

}; 

Node.h

#include "Node.h" 

std::ostream& operator<<(std::ostream& out, const Node& n) { 
    return out << &n << ": " << n.val << " -> " << n.next.get(); 
} 
+0

Sie sollten ** niemals ** auf dem Zeiger eines 'std :: unique_pointer'' delete' aufrufen. Überprüfen Sie Ihre 'int Deque :: remove_front()' Implementierung in Ihrer * Deque.cpp * – WhiZTiM

+0

Dann, wie der Destruktor Speicher von einem eindeutigen Zeiger freigegeben wird? – TigerCode

+0

@TigerCode http://en.cppreference.com/w/cpp/memory/unique_ptr – GMichael

Antwort

1

Sie haben hier UB:

std::unique_ptr<Node> new_node; 
new_node->val = move(a); 

Sie einen neuen Zeiger erstellen, die Standard (zeigt auf nullptr) und Sie dereferenzieren initialisiert ist. Sie sollten es mit std::make_unique initialisieren, wenn Sie C++ 14 oder höher oder es initialisieren mit new:

std::unique_ptr<Node> new_node = std::make_unique<Node>(); // C++14 or later 
std::unique_ptr<Node> new_node(new Node); // pre C++14 

Diese Linie auch Thema hat:

delete &old; 

diese Linie keinen Sinn macht. Sie erhalten die Adresse des Zeigers selbst, der als lokale Variable erstellt wurde, und versuchen, sie zu löschen. Wenn Sie versucht haben, Daten zu löschen, wo old zeigt, das ist Ether falsch - der ganze Punkt von std::unique_ptr ist das automatisch zu tun.

Dieses Mitglied:

std::unique_ptr<Node> tail ; 

das ist falsch von Design, wenn Sie es in Ihrem Code nicht zu verwenden scheinen. Dies setzt voraus, dass Sie mehrere std::unique_ptr haben, um auf dasselbe Objekt zu zeigen. Aber dieser Zeiger ist für eine eindeutige Eigentümerschaft.

Sie scheinen auch in Deque::size() Problem zu haben, aber ohne Quelle zu sehen ist es unmöglich zu sagen, was dort falsch ist.

In Ihrem Destruktor müssen Sie nichts tun (obwohl es nicht schaden würde, wenn andere Methoden korrekt implementiert werden) - zerstört alle Daten rekursiv.

+0

Ich habe vergessen, Größe() in der Post - ich habe es jetzt aufgenommen. Das ist, wo mein Debugger mich geführt hat. @Slava – TigerCode

+0

Ich glaube, es hat damit zu tun, wie ich den Knotenzeiger erstellt habe P – TigerCode

+0

@TigerCode 'size()' sieht OK aus, scheint es, dass Problem der Verwendung von 'nullptr' in' insert_front() 'es bricht. – Slava