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.

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top