C ++ copy-Konstrukt Konstrukts-and-assign Frage
-
20-09-2019 - |
Frage
Hier ist ein Auszug aus Artikel 56 des Buchs "C ++ Gotchas":
Es ist nicht ungewöhnlich, dass ein einfach zu sehen, Initialisierung eines Y-Objekt geschrieben ein von drei verschiedenen Arten, als ob sie waren gleichwertig.
Y a( 1066 );
Y b = Y(1066);
Y c = 1066;
In der Tat, alle drei dieser Initialisierungen wird wahrscheinlich zur Folge haben in den gleichen Objektcode Wesen erzeugt, aber sie sind nicht gleichwertig. Die Initialisierung eines wird als bekannt direkte Initialisierung, und es tut genau das, was könnte man erwarten,. Das Initialisierung wird bewerkstelligt durch ein direkter Aufruf von Y :: Y (int).
Die Initialisierungen von b und c komplexer. In der Tat sind sie zu Komplex. Diese sind beide Kopie Initialisierungen. Im Fall der Initialisierung von b, wir Ihr Interesse die Schaffung eines anonymen temporären vom Typ Y, mit dem Wert initialisiert, 1066. Wir verwenden dann diese anonymen vorübergehend als Parameter an die Kopie Konstruktor für Klasse Y zu initialisieren b. Schließlich rufen wir den destructor für die anonyme vorübergehend.
Um dies zu testen, habe ich eine einfache Klasse mit einem Datenteil (Programm am Ende angebracht ist), und die Ergebnisse waren überraschend. Es scheint, dass für den Fall c wird die Aufgabe durch den Copykonstruktor gebaut wurde, statt wie im Buch vorgeschlagen.
Weiß jemand, wenn die Sprache Standard geändert hat, oder ist dies einfach eine Optimierungsfunktion des Compilers? Ich wurde mit Visual Studio 2008.
Codebeispiel:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
Ausgabe:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
Ich war sehr überrascht von den Ergebnissen von d und e zu konstruieren. Um genau zu sein, erwartete ich ein leeres Objekt erstellt werden soll, und dann ein Objekt erstellt werden und auf das leere Objekt zugeordnet. In der Praxis wurden die Objekte von dem Copy-Konstruktor erstellt.
Lösung
Die Syntax
X a = b;
wobei a und b vom Typ X sind immer Kopie Konstruktion gemeint. Unabhängig von Varianten, wie zum Beispiel:
X a = X();
verwendet werden, gibt es keine Zuordnung geht, und nie gewesen. Baukonstruktion und assign wäre so etwas wie:
X a;
a = X();
Andere Tipps
Der Compiler ist erlaubt optimize Fälle b
und c
die gleichen wie a
zu sein. Des Weiteren kann Kopie Bau und Zuweisungsoperator Anrufe ganz ohnehin durch den Compiler beseitigt werden, so, was Sie sehen, ist nicht unbedingt das gleiche mit verschiedenen Compilern oder sogar Compiler-Einstellungen.
Wie von C ++ 17, alle drei von diesen sind Äquivalent (es sei denn, Y::Y(int)
ist explicit
, das würde einfach nicht zulassen c
) aufgrund dessen, was genannt wird, oft Pflichtexemplar elision .
Auch Y c = 1066;
schafft nur das eine Y
Objekt, weil das Ergebnis der impliziten Umwandlung in Y
ein prvalue ist, die verwendet wird c
zu initialisieren, anstatt eine temporäre zu erstellen.