Wie STL-Konstrukte verschachteln?
-
Hallo zusammen,
mich würde interessieren, wie man in C++ z.B. einen Vektor von Vektoren anlegt (oder eine Map mit Vektoren als Objekten u.dgl.)?
Wie sieht das denn syntaktisch korrekt aus?
Danke schon mal!
Ciao
-
std::vector< std::vector<std::string> >
wichtig ist das letzte leerzeichen.
-
vector< vector< vector< map< string, vector< pair< int, string > > > > > >
-
das letzte freizeichen ist wichtig, da >> (<< übrigens auch) ein shift operator ist und der darf (normalerweise) natürlich an der stelle nicht im programm stehen.
-
Danke für die Tips!
Aber noch eine Frage: Wie macht man denn Zugriffe auf solche verschachtelten Maps, Vektoren etc.?
Komme mit der Notation und den Konzepten bei STL nicht so ganz klar (da ich von Java komme). Verstehe nicht, dass ich wenn ich mit nem Schlüssel in ne Map gehe nicht den Wert bekomme (so wie ich es intuitiv erwarte), sondern ein pair aus Key und Value? Ist doch an der Stelle eigentlich überflüssig, da ich den Schlüssel ja schon habe!
Ciao
-
Naja, ob deine Logic verständlicher ist, ist ja nicht gesagt.
Die STL hat ein bestimmtes Konzept, nämlich das die Schnittstelle ein Iterator ist. Du bekommst einen Iterator zurück, wenn du auf die Map über den Key gehst. Mit diesem kannst du dann explizit mit second auf den Wert zugreifen. Weil wenn du implizit einen Wert zurück bekommen würdest, wie würdest du z.B. das nächste Element bekommen, wenn du nur den Schlüssel des vorherigen hast? Wäre schlecht. So ist es ab viel flexibler, da du über den Iterator weitere Aktionen machen kannst, wie du es gerne willst.
m1.find(4)->second; // value von key 4. m1.find(4)++; // nächstes map-Element hinter 4.
Das gleiche Konzept ist übrigens bei den anderen Containern auch.
-
Danke für die Erläuterung. Aber in Java ist es ähnlich (mal von der fehlenden Typisierung in den Versionen < 1.5 abgesehen).
Du kannst mit dem Key direkt auf ein Element zu greifen:Object element = map.get(key);
Wenn Du die Map durchlaufen willst, kannst Du Dir einen Iterator der Keys geben lassen:
Iterator keys = map.keySet().iterator();
Mit dem Iterator kannst Du dann z.B. in einer for-Schleife über alle Schlüssel laufen. Auf Wunsch kann Dir eine Map auch ein entrySet() zurückgeben, hab ich noch nie benutzt, aber die Beschreibung deutet darauf hin, dass das ungefähr allen pair-Einträgen der STL-Map entspricht. Zusätzlich gibt es noch die Möglichkeit, sich alle Werte zu den Keys in der Map ausgeben zu lassen.
In Java ist die Map aber unsortiert. Es gibt aber auch sortierte Map-Varianten.Eine Frage noch: Wie kann ich denn auf verschachtelte Maps zugreifen?
In meinem Bsp.:map<int, map<int, map<int, Object*> > > map;
Geht das so:
Object *object = (((map[1]->second)[2]->second)[3])->second;
?
Ciao
-
fast richtig - entweder du nutzt die find-Methode der map, die einen Iterator auf Schlüssel/Wert-Paar zurückliefert oder den Index-Operator, der dir den zum Schlüssel passenden Wert gibt:
map<int,map<int,Object*> mymap; ... Object* ob1=mymap[1][2];//ja, das geht wirklich und erzeugt die erforderten Elemente, wenn sie noch nicht existieren Object* ob2=mymap.find(1)->second.find(2)->second;//da ergibt einen Laufzeitfehler, wenn die angeforderten Elemente nicht existieren
-
Danke!
Und wie bekomm ich son Zeiger in ne verschachtelte Map?
Object *object ... mymap[1][2] = object;
?
Und vor allem, wie verwende ich Methoden wie erase? So wie find, also:
mymap.find(1)->second.erase(2);
Was passiert eigentlich wenn ich so ein Konstrukt anlege:
map<int, map<int, Object *> >;
?
Werden die Maps dann schon leer angelegt und der Speicher reserviert, oder werden die Maps dann angelegt, wenn das erste Mal Einträge in sie geschrieben werden?
Wenn ich mit dem obigen Konstrukt Einträge lösche und die innere Map leer wird, sollte ich sie dann aus der äußeren entfernen, oder ist das egal?Danke schon mal!
Ciao
-
Reth schrieb:
Danke!
Und wie bekomm ich son Zeiger in ne verschachtelte Map?
Object *object ... mymap[1][2] = object;
?
Dürfte korrekt sein.
Und vor allem, wie verwende ich Methoden wie erase? So wie find, also:
mymap.find(1)->second.erase(2);
Fast - erase erwartet keinen Schlüsselwert, sondern einen Iterator:
mymap.find(1)->second.erase(mymap.find(1)->second.find(2));
Was passiert eigentlich wenn ich so ein Konstrukt anlege:
map<int, map<int, Object *> >;
?
Werden die Maps dann schon leer angelegt und der Speicher reserviert, oder werden die Maps dann angelegt, wenn das erste Mal Einträge in sie geschrieben werden?
Das legt die äußerste Map ohne Einträge an. Erst wenn du in der äußersten Map etwas einfügst, legst du die dazugehörige innere Map an.
Wenn ich mit dem obigen Konstrukt Einträge lösche und die innere Map leer wird, sollte ich sie dann aus der äußeren entfernen, oder ist das egal?
Das kommt ganz auf deine Anwendung an - solange du das Paar <x,leere Map> noch in der äußeren Map hast, kannst du auch noch darauf zugreifen - wenn du es löschst, liefert das nächste "mymap.find(x)" end() zurück.
-
CStoll schrieb:
Und vor allem, wie verwende ich Methoden wie erase? So wie find, also:
mymap.find(1)->second.erase(2);
Fast - erase erwartet keinen Schlüsselwert, sondern einen Iterator:
mymap.find(1)->second.erase(mymap.find(1)->second.find(2));
Danke für die Antworten.
Laut SGI gibts für map aber auch ein erase mit key:size_type erase(const key_type& k)
Ciao
-
Reth schrieb:
Danke für die Antworten.
Laut SGI gibts für map aber auch ein erase mit key:size_type erase(const key_type& k)
Ciao
Ups, stimmt ja, wie konnte ich den nur übersehen?
*im Boden versinkt*
-
Naja, die SGI-Doku ist aber für die SGI-STL, die sich von der ISO-C++ Standardlib an einigen Stellen unterscheiden kann. Will jetzt nicht sagen, das es in diesem Fall so ist, aber die SGI-Docu als Referenz heranzuziehen, kann auch ins Auge gehen.
-
Artchi schrieb:
Will jetzt nicht sagen, das es in diesem Fall so ist, aber die SGI-Docu als Referenz heranzuziehen, kann auch ins Auge gehen.
In dem Fall stimmt es aber überein - die erase(const key_type&) Methode gehört zum ANSI Standard (23.1.2).
-
Wo gibts denn ne gute Beschreibung des ANSI-/ISO-Standards der STL?
Hier vielleicht:
http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
?
-
google dürfte sicher was dazu bringen
(ich hab's in Buchform zu Hause stehen - ein ziemlich dicker Wälzer btw)
-
Dinkumware ist schon ne gute Anlaufstelle. Ansonst ist die MSDN auch sehr informativ, vorallem hat sie auch Beispielcodes zu jedem Std-Lib-Thema.
Ich pers. bevorzuge aber vernünftige Bücher aus Papier, z.B. das Buch von Kuhlins und Schrader -> super!
-
Buchtechnisch hab ich bisher Primer C++ und Thinking in C++ Volume 1.
Nehm ich beide aber hauptsächlich als Nachschlagewerke, statt sie mal zu studieren.
-
Jetzt nochmal ne Frage zu verschachtelten Maps usw.:
Muss ich bei sowas:
map<int, map<int, MyObject *> > map;
Zum Durchlaufen zwei verschachtelte For-Schleifen machen, die jeweils über einen Iterator der äußeren und einen der inneren Map laufen oder geht das auch anders?
Und was geschieht denn, wenn ich Zeiger von MyObject in 2 Klassenvariablen, einmal in ne Map und einmal in nen Vector lege, da ich mal die eine, mal die andere Zugriffsart benötige, also z.B.:
vector<MyObject *> vec; map<int, map<int, MyObject *> > map; ...
Im Destruktor durchlaufe ich dann den Vector mit seinem Iterator und mache ein erase auf jeden Eintrag, da Objekte vom Typ MyObject zur Laufzeit dynamisch erzeugt und in beide Konstrukte eingetragen werden.
Muss ich mich dann um die Maps auch noch kümmern, oder kann ich die ignorieren?
Vielen Dank schon einmal, hoffe die Fragen sind nicht zu banal oder anfängermäßig!
Ciao
-
Reth schrieb:
Jetzt nochmal ne Frage zu verschachtelten Maps usw.:
Muss ich bei sowas:
map<int, map<int, MyObject *> > map;
Zum Durchlaufen zwei verschachtelte For-Schleifen machen, die jeweils über einen Iterator der äußeren und einen der inneren Map laufen oder geht das auch anders?
Ja, mußt du. (btw solltest du die Variable nicht "map" nennen, das gibt Konflikte mit dem gleichnamigen Typ ;))
for(map<int,map<int,MyObject*> >::iterator outer=mymap.begin();outer!=mymap.end();++outer) for(map<int,MyObject*>::iterator inner=outer->second.begin();inner!=outer->second.end();++inner) print(*(inner->second));
Und was geschieht denn, wenn ich Zeiger von MyObject in 2 Klassenvariablen, einmal in ne Map und einmal in nen Vector lege, da ich mal die eine, mal die andere Zugriffsart benötige, also z.B.:
Dann mußt du das entsprechende Objekt trotzdem genau einmal löschen - und am besten dafür sorgen, daß der Zeiger aus beiden Containern gelöscht wird.
Muss ich mich dann um die Maps auch noch kümmern, oder kann ich die ignorieren?
delete brauchst du in der map nicht mehr - aber du mußt den Zeiger dort auch rauswerfen, wenn du das zugehörige Objekt demontiert hast.
(eine bessere Alternative wäre es, boost::shared_ptr zu verwenden)