2016-05-13 6 views
-1

Ich stehe vor dieses Problem, wenn ich ein Element aus meiner Liste entfernen.Fehler EXC_BAD_ACCESS in Liste mit SmartPointer

Hier mein list.h:

class AwesomeList { 
friend class Iteratore; 
private: 
class Nodo; 

class SmartPointer { 
public: 
    Nodo* punt; 

    SmartPointer(Nodo* n = 0): punt(n) {} 
    SmartPointer(const SmartPointer& ptr): punt(ptr.punt) {} 
    ~SmartPointer() { 
     delete punt; 
    } 

    SmartPointer& operator=(const SmartPointer& ptr) { 
     if (this != &ptr) { 
      delete punt; 
      punt = ptr.punt; 
     } 
     return *this; 
    } 
    bool operator==(const SmartPointer& ptr) const { 
     return ptr.punt == punt; 
    } 
    bool operator!=(const SmartPointer& ptr) const { 
     return ptr.punt != punt; 
    } 
    Nodo* operator->() const { 
     return punt; 
    } 
    Nodo& operator*() const { 
     return *punt; 
    } 
}; 

class Nodo { 
public: 
    T* value; 
    SmartPointer next; 

    Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr) {} 
}; 

SmartPointer head; 
SmartPointer tail; 

public: 
class Iteratore{ 
    friend class AwesomeList; 
private: 
    AwesomeList::SmartPointer punt; 
public: 
    bool operator==(const Iteratore& it) const { 
     return it.punt == punt; 
    } 
    bool operator!=(const Iteratore& it) const { 
     return it.punt != punt; 
    } 
    Iteratore& operator++() { 
     if(punt != 0) punt = punt->next; 
     return *this; 
    } 
    Iteratore& operator++(int) { 
     if(punt != 0) punt = punt->next; 
     return *this; 
    } 
    T* operator*() const { 
     if (punt != 0) return punt->value; 
    } 
}; 

AwesomeList(const SmartPointer& ptr = 0): head(ptr), tail(0) { 
    if (head != 0) { 
     SmartPointer p = head; 
     while (p != 0) 
      p = p->next; 
     tail = p; 
    } 
} 
AwesomeList(const AwesomeList& list): head(list.head), tail(list.tail) {} 

AwesomeList& operator=(const AwesomeList& list) { 
    head = list.head; 
    tail = list.tail; 
} 

int getSize() const { 
    int count = 0; 
    SmartPointer p = head; 
    while (p != 0) { 
     p = p->next; 
     count++; 
    } 
    return count; 
} 
bool isEmpty() const { 
    return getSize() == 0; 
} 
T* at(int pos) const { 
    if (pos > -1 && pos < getSize()) { 
     SmartPointer p = head; 
     while (pos--) { 
      p = p->next; 
     } 
     return p->value; 
    } else return 0; 
} 
void add(const T& t) { 
    if (head == 0) { 
     head = SmartPointer(new Nodo(&(const_cast<T&>(t)))); 
     tail = head; 
    } else { 
     tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t)))); 
     tail = tail->next; 
    } 
} 
void remove(int pos) { 
    if (pos > -1 && pos < getSize()) { 
     SmartPointer newHead = head; 
     SmartPointer p = newHead; 
     head = 0; 
     while (pos--) { 
      add(*p->value); 
      p = p->next; 
     } 
     p = p->next; 
     while (p != 0) { 
      add(*p->value); 
      p = p->next; 
     } 
    } 
} 
void replace(int pos, T* t) { 
    if (pos > -1 && pos < getSize()) { 
     SmartPointer p = head; 
     while (pos--) 
      p = p->next; 
     p->value = t; 
    } 
} 
void replace(int pos, const T& t) { 
    if (pos > -1 && pos < getSize()) { 
     SmartPointer p = head; 
     while (pos--) 
      p = p->next; 
     T& t_obj = const_cast<T&>(t); 
     p->value = &t_obj; 
    } 
} 

Iteratore begin() const { 
    Iteratore it; 
    it.punt = head; 
    return it; 
} 
Iteratore end() const { 
    Iteratore it; 
    it.punt = 0; 
    return it; 
} 
T* operator[](const Iteratore& it) const { 
    return it.punt->value; 
} 
}; 

Das sind die Tests, die ich gemacht:

AwesomeList<int> list = AwesomeList<int>(); 
list.add(1); 
list.add(2); 
list.add(3); 
for (int i = 0; i < list.getSize(); i++) 
    qDebug() <<*(list.at(i)) <<" "; 

list.remove(-1); 
for (int i = 0; i < list.getSize(); i++) 
    qDebug() <<*(list.at(i)) <<" "; 

list.remove(2); 
for (int i = 0; i < list.getSize(); i++) 
    qDebug() <<*(list.at(i)) <<" "; 

list.replace(0, 5); 
qDebug() <<"Replace in posizione 0"; 
auto cit = list.begin(); 
for (; cit != list.end(); cit++) 
    qDebug() <<*(*cit) <<" "; 

qDebug() <<"Size"; 
qDebug() <<list.getSize() <<endl; 

Dies ist die Linien, wo Fehler erscheint:

  • AwesomeList :: Nodo: : ~ Nodo() + 16 (awesomelist.h: 8)
  • AwesomeList :: SmartPointer :: ~ SmartPointer() + 42 (awesomelist.h: 21)
  • AwesomeList :: Intelligenter Zeiger :: ~ Intelligenter Zeiger() + 21 (awesomelist.h: 22)

Jede Hilfe ist zu schätzen. Vielen Dank!

UPDATE

ich mein Problem gelöst Intelligenter Zeiger und Nodo Klassen wie folgt zu ändern:

SmartPointer(Nodo* n = 0): punt(n) { 
     if (punt) punt->references++; 
    } 
    SmartPointer(const SmartPointer& ptr): punt(ptr.punt) { 
     if (punt) punt->references++; 
    } 
    ~SmartPointer() { 
     if (punt) { 
      punt->references--; 
      if (punt->references == 0) delete punt; 
     } 
    } 

    SmartPointer& operator=(const SmartPointer& ptr) { 
     if (this != &ptr) { 
      Nodo* n = punt; 
      punt = ptr.punt; 
      if (punt) punt->references++; 
      if (n) { 
       n->references--; 
       if (n->references == 0) delete n; 
      } 
     } 
     return *this; 
    } 
    bool operator==(const SmartPointer& ptr) const { 
     return ptr.punt == punt; 
    } 
    bool operator!=(const SmartPointer& ptr) const { 
     return ptr.punt != punt; 
    } 
    Nodo* operator->() const { 
     return punt; 
    } 
    Nodo& operator*() const { 
     return *punt; 
    } 
}; 

class Nodo { 
public: 
    T* value; 
    SmartPointer next; 
    int references; 

    Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr), references(0) {} 
}; 
+0

Die Fehlerliste enthält nicht die tatsächlichen Fehler. – vu1p3n0x

+0

Der Fehler ist EXC_BAD_ACCESS. – Daniele

+0

Mein Freund, ich denke, Sie versuchen uns zu täuschen. 'SmartPointer head;' kann nicht mit nur einer Vorwärtsdeklaration von 'SmartPointer' kompiliert werden. Sie benötigen die vollständige Definition von 'SmartPointer', um einen' SmartPointer' zu instanziieren. – user4581301

Antwort

1

Sorry, aber ich verstehe nicht, das Verhältnis unter Ihrer SmartPointer Klasse.

Es trägt einen Zeiger auf Nodo und delete es mit dem Konstruktor. Gut.

Aber, wenn ich mich nicht falsch

(1), wenn Sie ein SmartPointer mit Copykonstruktor erstellen, kopieren Sie den Zeiger von den SmartPointer kopiert, so dass Sie mit einem punt mit dem gleichen Wert zwei bezwecken; Wenn Sie die zwei Objekte zerstören, rufen Sie delete zweimal über den gleichen Zeiger auf; dies kann das Programm abstürzen

(2), wenn Sie operator= nennen, haben Sie das gleiche Problem mit dem Copy-Konstruktor, aber darüber hinaus Sie nicht löschen den alten spitzen Wert

von Beispiel sehen add()

head = SmartPointer(new Nodo(&(const_cast<T&>(t)))); 
    tail = head; 

Sie erstellen ein temporäres SmartPointer Objekt, um es mit new Nodo(&(const_cast<T&>(t))) initialisiert. Als nächstes kopieren Sie dieses temporäre Objekt in head, so dass sowohl head als auch das temporäre Objekt denselben Nicht-NULL-Zeiger enthalten. Jetzt wird das temporäre Objekt zerstört, so dass der Speicher, auf den punt zeigt, gelöscht wird, aber head (sein punt) zeigt weiterhin auf einen Speicherbereich, der gelöscht wird. Jetzt kopieren Sie head in tail, und Sie haben beide head und tail, die auf den gleichen gelöschten Bereich zeigen.

Blick auf die sonst Fall

tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t)))); 
    tail = tail->next; 

In diesem Fall tail->next (und nehmen in Anzahl, die take Punkt auf gelöschten Bereich) einen Zeiger von einem temporären Objekt empfangen, die sie löschen. Sie schreiben also in einen gelöschten Bereich einen Zeiger, der sofort gelöscht wird.

Ich hoffe, es ist klar, wie viel das alles gefährlich ist.

Vorschlag: Redesign SmartPointer Klasse.

ps.entschuldigung für mein schlechtes Englisch.

+0

Sie wurden sehr geklärt. Vielen Dank! Ihrer Meinung nach, wenn ich ein privates Feld SmartPointer * Kopf verwende, und dann schreibe ich Kopf = neuer SmartPointer (...), könnte mein Problem lösen? – Daniele

+0

Denken Sie einen Moment an die Logik. Sie möchten einen rohen Zeiger auf einen intelligenten Zeiger erstellen. Dies vereitelt den Punkt des intelligenten Zeigers. Max ist richtig. Sie müssen 'SmartPointer' re-implementieren, es zu [Regel der 5-Kompatibilität] (http://en.cppreference.com/w/cpp/language/rule_of_three) und [move-Semantik verwenden] (http: // stackoverflow com/questions/3106110/Was-sind-Bewegung-Semantik). Eine Alternative ist [use 'std :: unique_ptr'] (http://en.cppreference.com/w/cpp/memory/unique_ptr) anstelle von' SmartPointer'. – user4581301

+0

Ja, hast du recht. Irgendein Vorschlag? PS: Ich habe meinen Code mit einem korrekten Operator = aktualisiert. – Daniele