2015-06-07 14 views
6

diesen Code vor:Unechte Kopien in C++ 03 libstdC++ vs C++ 11

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() : _x(0) 
    { 
     cout << "Default" << endl; 
    } 
    Foo(int a) : _x(a) 
    { 
     cout << "Param" << endl; 
    } 

    Foo(Foo const &foo) : 
     _x(foo._x) 
    { 
     cout << "Copy" << endl; 
    } 

    Foo& operator=(Foo const &foo) 
    { 
     cout << "Assignment" << endl; 
     _x = foo._x; 
     return *this; 
    } 

    int get(void) 
    { 
     return _x; 
    } 

private: 
    int _x; 
}; 

int main(int argc, char *argv []) 
{ 
    std::map<int, Foo> foos; 

    Foo a_foo(10); 

    foos[100] = a_foo; 

    return 0; 
} 

Zusammengestellt in gcc mit -std = C++ 11 und Sie die Ausgabe erhalten,

Param 
Default 
Assignment 

Remove -std = C++ 11, dann erhalten Sie,

Param 
Default 
Copy 
Copy 
Assignment 

with c++11

without

libc++ example producing the superior output in c++03 mode

Wo sind die beiden kommen zusätzliche Kopien?

Sie beziehen sich auf den Aufruf des Subscript-Operators, nicht die Zuweisung. (Sie bleiben, wenn Sie die Aufgabe entfernen.) Für mich scheinen sie selbst in einer Welt vor C++ 11 nicht benötigt zu werden, wie das Beispiel libC++ zeigt.

Das ursprünglich durch einen Blick auf this question

+2

Sie erhalten sie nicht in C++ 11-Modus so, warum alle nicht entfernen Sie die R-Wert-ref Funktionen von der Frage vollständig? Die Frage wird von ihnen offensichtlich nicht berührt. –

+0

Ich erwarte, dass dies eine QoI-Sache innerhalb von libstdC++ ist und rate mal, dass es etwas dauern würde, um sinnlos genau festzustellen, was vor sich geht. –

+0

@LightnessRacesinOrbit Sie sind da, denn die Frage wird von ihnen nicht beeinflusst, im Widerspruch zu der früheren Antwort. – tahsmith

Antwort

9

ist LWG 334 Das motiviert war:

Die C++ 03 Standard-Mandate folgende Effekte für operator[] ([lib.map.access] p1):

Rücksendung:(*((insert(make_pair(x, T()))).first)).second.


libstdC++ implementiert die Insertion von operator[] verwendet (in dem Fall, in dem der Schlüssel noch nicht vorhanden ist), wie C++ 03-Modus folgt:

__i = insert(__i, value_type(__k, mapped_type())); 

__i ist der Einfügepunkt wird es als

iterator __i = lower_bound(__k); 

__k ist der Parameter, der berechnet operator[].

Die Erstellung des temporären value_type(__k, mapped_type()) verursacht die erste Kopie (von mapped_type() in das value_type Paar). Die zweite Kopie ist das Ergebnis von insert, das das value_type-Paar in einen tatsächlichen Knoten kopiert.

Die ursprüngliche Version von 1997 ist: (!, Die nicht einmal damals noch nicht gab)

return (*((insert(value_type(k, T()))).first)).second; 

, die fast bis auf den Buchstaben der Norm ist. Das letzte Mal geändert wurde deutlich im Jahr 1998 war Davor, es verwendet:

__i = insert(__i, value_type(__k, _Tp())); 

Die Commit-Nachricht sagt dieser

Update auf SGI STL 3.11

war.


Earlier versions of the SGI STL (1995) tatsächlich map::operator[] in der gleichen Weise wie die C++ 03 Standard-angab:

Für eine Karte m und Schlüssel k, m[k]-(*((m.insert(make_pair(k, T()))).first)).second semantisch äquivalent ist.

SGI STL v2.03 (1997) hatte bereits geschaltet value_type statt make_pair zu verwenden. Und wie das gcc Commit-Protokoll andeutet, hat sich die SGI STL-Implementierung zwischen v3.0 (ebenfalls 1997) und v3.11 (1998) von insert(value_type(.. wieder in das noch in libstdC++ vorhandene Formular geändert, wobei lower_bound verwendet wurde und das Paar nur erstellt wurde, wenn der Schlüssel nicht existiert noch.


So könnte man sagen, dass libstdC++ implementiert die erste vorgeschlagene Auflösung von LWG 334 (value_type statt make_pair). Dies ist jedoch nicht genau das, was passiert ist, wenn man seine Geschichte betrachtet. Es folgt einfach SGI STL. libC++ entspricht in dieser Hinsicht nicht genau C++ 03.


libstdC++ C++ 11 Version des gleichen Operators verwendet eine benutzerdefinierte Einlagerungsfunktion. Die C++ 11 Standardspezifikation von map::operator[] folgt die vorgeschlagene Auflösung von LWG 334:

Effekte: Wenn kein Schlüssel entspricht x in der Karte ist, fügt value_type(x, T()) in die Karte.

(wo x ist der Parameter von operator[])

+0

Soweit ich das beurteilen kann, hat C++ 03 die Auswirkungen von 'map :: operator []' im Vergleich zu C++ 98 nicht verändert. – dyp

+0

Danke, das war interessant und gründlich. In C++ 11 scheint der Wortlaut von Effekten wie in LWG 334 zu sein. – tahsmith

+0

@tahsmith Ja, ich habe dort ein bisschen früher aufgehört.Ich habe jetzt den C++ 11-Wortlaut eingefügt. Es war auch sehr interessant, in gcc's Geschichte zu gucken! Zum Glück erinnerte ich mich daran, dass es ein LWG-Problem gab, das sich auf "operator []" bezog, weshalb es nicht allzu schwierig war, LWG 334 zu finden. – dyp

Verwandte Themen