2009-11-17 2 views
5

Ich ging durch Josuttis "Verwendung von Karten als assoziative Arrays" (von The C++ Standard Library - A Tutorial and Reference, 2nd Edition) und stieß auf Using a std::map as an associative array auf Stack Overflow. Jetzt habe ich mehr Fragen zu den Konstruktoren, die beim Einfügen in eine Map aufgerufen werden.Brauchen Sie Hilfe zu verstehen mit C++ Map als assoziative Array

Hier ist mein Beispielprogramm (nicht am besten Praktiken Codierung verwendet; mich bitte entschuldigen, dass):

class C 
{ 
public: 

    string s; 

    C() { cout << "default " << endl;} 

    C(const string& p) : s(p) 
    { cout << "one param" << endl;} 

    C(const C& obj) 
    { 
     if (this != &obj) 
     { 
     s = obj.s; 
     } 
     cout << "copy constr" << endl; 
    } 

    C& operator = (const C& obj) 
    { 
     if (this != &obj) 
     { 
      s = obj.s; 
     } 
     cout << "copy initializer" << endl; 
     return *this; 
    } 
}; 

int main() 
{ 
    map<int,C> map1; 
    C obj("test"); 

    cout << "Inserting using index" << endl; 
    map1[1] = obj; 

    cout << "Inserting using insert/pair" << endl; 
    map1.insert(make_pair(2,obj)); 
} 

Die Ausgabe für dieses Programm ist:

one param 
Inserting using index 
default 
copy constr 
copy constr 
copy initializer 
Inserting using insert/pair 
copy constr 
copy constr 
copy constr 
copy constr 

Ich war die Annahme, dass die Initialisierung map by index sollte den Standardkonstruktor und anschließend den Zuweisungsoperator aufrufen.

Aber Ausführung map1[1] = obj erstellt folgenden Ausgang;

Inserting using index 
default 
copy constr 
copy constr 
copy initializer 

Kann mir jemand helfen, die Initialisierung besser zu verstehen?

+0

Sie legen nicht für die Kopie Konstruktion selbst testen müssen. –

+0

In der Tat, jetzt verstehe ich, dass es besser ist, Zeiger als Objekte in STL-Containern zu haben. – mithuna

+1

@mithuna: Warnung: Das Speichern von Zeigern anstelle von Objekten bringt lebenslange Probleme mit der Verwaltung mit sich, daher würde ich sagen, dass es besser ist, Objekte zu speichern. * Wenn * dies Leistungsprobleme verursacht, sollten Sie sehen, ob die Kopie optimiert werden kann. Dann, wenn es nicht möglich ist, könnten Sie in Erwägung ziehen, Zeiger anstelle von Objekten zu speichern. In diesem Fall könnten Sie an der Boost.PointerContainer-Bibliothek interessiert sein (http://www.boost.org/doc/libs/1_40_0/libs/ptr_container/doc/ptr_container.html). ptr_map (http://www.boost.org/doc/libs/1_40_0/libs/ptr_container/doc/ptr_map.html), im vorliegenden Fall. –

Antwort

7

Wenn Sie die Spezifikation für std :: map lesen, heißt es, dass Operator [] entspricht (in diesem Fall)

(*((this->insert(make_pair(1,C()))).first)).second 

So erklärt dies alles Konstruktor ruft Sie sehen. Zuerst ruft es den Standardkonstruktor C() auf. Dann ruft es make_pair auf, das das C-Objekt kopiert. Dann ruft es insert auf, wodurch eine Kopie des gerade erstellten Paarobjekts erstellt wird und der C-Kopierkonstruktor erneut aufgerufen wird. Schließlich ruft es den Zuweisungsoperator auf, um das eingefügte Objekt auf das Objekt zu setzen, dem Sie es zuweisen.

+0

Schön und prägnant. –

+0

Wie meine Antwort, nur besser! +1 und meine gelöscht. –

+0

Schöne Antwort, lesen Sie die Spezifikation und es machte jetzt viel Sinn. – mithuna

0

Was passiert, wenn Sie einfach map[1]; ausführen? Dies kann interne Kopien erfordern, abhängig von der Implementierung von map, die Ihre Standardbibliothek verwendet.

2

Nicht wissen. Aber das ist interessant:

#include <string> 
#include <map> 
#include <iostream> 
using namespace std; 

class C 
{ 
    public: 
     string s; 
     C() 
     { 
      cout << "default " << endl; 
     } 
     C(const string& p) 
     : s(p) 
     { 
      cout << "one param(" << s << ")" << endl; 
     } 
     C(const C& obj) 
      :s(obj.s) 
     { 
      cout << "copy constr(" << s << ")" <<endl; 
     } 
     C& operator = (const C& obj) 
     { 
      cout << "copy initializer\t" <<; 

      C copy(obj); 
      std::swap(s,copy.s); 

      return *this; 
     } 
}; 

int main() 
{ 
    map<int,C> map1; 
    cout << "Inserting using index" << endl; 
    map1[1] = C("Plop"); 
} 

Es ist wie der Standard sucht man wird um erstellt und kopiert.
Dann wird das externe einfach über es hinausgeworfen, sobald es an Ort und Stelle ist.

Inserting using index 
default 
copy constr() 
copy constr() 
one param(Plop) 
copy initializer  copy constr(Plop)