2008-12-14 14 views
6

Ich brauche Listen für mein Programm und musste entscheiden, ob ich std :: vector oder std :: list verwenden. Das Problem mit dem Vektor ist, dass es keine Entfernungsmethode gibt und bei der Liste gibt es keinen Operator []. Also habe ich beschlossen, eine eigene Klasse zu schreiben, die std :: list erweitert und den Operator [] überlädt.Erweitern std :: list

Mein Code sieht wie folgt aus:

#include <list> 

template <class T > 
class myList : public std::list<T> 
{ 
public: 
T operator[](int index); 
T operator[](int & index); 
myList(void); 
~myList(void); 
}; 

#include "myList.h" 

template<class T> 
myList<T>::myList(void): std::list<T>() {} 

template<class T> 
myList<T>::~myList(void) 
{ 
std::list<T>::~list(); 
} 

template<class T> 
T myList<T>::operator[](int index) { 
int count = 0; 
std::list<T>::iterator itr = this->begin(); 
while(count != index)itr++; 
return *itr;  
} 

template<class T> 
T myList<T>::operator[](int & index) { 
int count = 0; 
std::list<T>::iterator itr = this->begin(); 
while(count != index)itr++; 
return *itr; 
} 

Ich kann es kompilieren, aber ich bekomme einen Linker-Fehler, wenn ich versuche, es zu benutzen. Irgendwelche Ideen?

+0

Sie haben 'T Operator [] (int index);' und 'T Operator [] (int & index);' Sie können aber möchte stattdessen 'T & operator [] (int index)' und 'const T & operator [] (int index) const 'verwenden. Innerhalb dieser Funktionen können Sie auch 'while (index -)' anstelle einer neuen Variablen verwenden, um die Anzahl zu überwachen. – Dennis

Antwort

10

Der gesamte Vorlagencode sollte in die Header-Datei geschrieben werden. Dieses Füll-Fix-Linking-Problem (das ist der einfachste Weg). Der Grund dafür ist, dass Compiler jede Quelldatei (.cc) separat von anderen Dateien kompiliert. Auf der anderen Seite muss es wissen, welchen Code es genau zu erstellen hat (dh wofür wird die T in-Vorlage verwendet), und es hat keine andere Möglichkeit, es zu kennen, es sei denn, der Programmierer teilt es explizit mit oder enthält den gesamten Code als Vorlage Instanziierung geschieht. I.e. Wenn mylist.cc kompiliert wird, weiß es nichts über Benutzer von mylist und welchen Code muss erstellt werden. Wenn listuser.cc hingegen kompiliert wird und der gesamte Mist-Code vorhanden ist, erstellt der Compiler den benötigten Mist-Code. Sie können mehr darüber in here oder in Stroustrup lesen.

Ihr Code hat Probleme, was passiert, wenn der Benutzer eine negative oder zu große Anfrage (mehr als die Anzahl der Elemente in der Liste) anfordert. Und ich habe nicht viel gesehen.

Außerdem weiß ich nicht, wie u planen, es zu benutzen, aber Ihr Operator [] ist O (N) Zeit, die wahrscheinlich leicht auf O (N * N) führen Schleifen ...

+1

"Ihr Operator [] ist O (N) time" - genau deshalb ist er nicht in der 'std :: list <>' des Standards enthalten. –

6

Vektoren haben die erase method, die Elemente entfernen können. Reicht das nicht aus?

+0

Es ist nicht so einfach zu verwenden wie die Methode remove in std :: list –

+0

Dann verwenden Sie stattdessen std :: remove? –

+0

Ich wusste nichts darüber. Ich werde es betrachten –

1

Sie müssen Ihren gesamten Vorlagencode in die Kopfzeile verschieben.

21

Angesichts Ihrer ursprünglichen Problemstellung,

Ich brauche Listen für mein Programm und musste entscheiden, ob ich std :: vector oder std :: list verwenden. Das Problem mit Vektor ist, dass es keine Methode zum Entfernen gibt und dass es in der Liste keinen Operator [] gibt.

gibt es keine Notwendigkeit, Ihre eigene Liste Klasse zu erstellen (dies ohnehin keine kluge Design Wahl ist, weil std::list, das ein starker Hinweis darauf ist keinen virtuellen Destruktor haben, dass es nicht als verwendet werden soll Basisklasse).

Mit den Funktionen std::vector und std::remove können Sie immer noch erreichen, was Sie wollen. Wenn v eine std::vector<T> ist, dann wird der Wert entfernen value, können Sie einfach schreiben:

#include <vector> 
#include <algorithm> 
T value = ...; // whatever 
v.erase(std::remove(v.begin(), v.end(), value), v.end()); 
+0

Das sollte sein: v.resease (std :: remove (v.begin(), v.end(), Wert), vec.end()); – dalle

+0

Sie haben natürlich Recht. Vielen Dank. – ChrisN

+0

Und eine einzelne Elementversion: v.resease (std :: find (...)); –

1

Die offensichtliche Sachen bereits in Einzelheiten beschrieben:

Aber die Methoden, die Sie wählen, zu implementieren ??

  • Destructor.
    • Nicht erforderliche Compiler wird das für Sie generieren.
  • Die zwei verschiedenen Versionen von operator [] sind sinnlos
    • Auch sollten Sie uisng std :: list :: size_type als Index
    • Es sei denn, Sie eine negative Indizes unterstützen möchten sein.
  • Es gibt keine const Versionen Operator []
  • Wenn Sie [] implementieren wollen Sie sollten auch tun()
  • Sie verpassten die verschiedenen Möglichkeiten, eine Liste aufzubauen.
  • Container intern verschiedene Arten der beste Weg, um einen Standard-Container zu erweitern ist nicht durch Ableitung, aber das Schreiben frei Funktionen
5

Neben anderen ausgezeichneten Kommentare definieren sollten. Sehen Sie sich zum Beispiel an, wie Boost String Algorithms verwendet werden kann, um std::string und andere String-Klassen zu erweitern.

0

Es ist nicht notwendig, den Destruktor von std :: list aufzurufen, da Sie bereits von std :: list ableiten, wenn der Destruktor für myList automatisch aufgerufen wird. Std :: list destructor wird aufgerufen.

+0

Beachten Sie, dass std :: list keinen virtuellen Destruktor hat. – gbjbaanb

+0

Ein Mangel des virtuellen Destruktors wäre nur dann ein Problem, wenn er versucht hätte, ein Objekt von myList durch einen Zeiger auf std :: list zu löschen, was sowieso eine seltsame Verwendung eines Containers wäre. –

+0

wahr, aber es lohnt sich trotzdem, daran zu erinnern. – gbjbaanb

52

Je nach Ihren Anforderungen sollten Sie std::vector verwenden (wenn Sie oft am Ende, und Random Access), oder std::deque (wenn Sie oft am Ende oder am Anfang und/oder Ihre Dateien anfügen oder entfernen müssen) Dataset ist riesig und will immer noch wahllos zugreifen). Hier ist ein gutes Bild zeigt Ihnen, wie die Entscheidung treffen:

Container Choice http://adrinael.net/containerchoice.png

+1

Das ist toll, vor allem, wenn Sie sich die Zeit genommen haben, es zu machen! +1 – Samaursa

Verwandte Themen