Wenn Sie einen öffentlichen Kopierkonstruktor haben, wird das kleine Programm erstellt kompilieren, aber nicht den Nebeneffekt "Kopieren" anzeigen.
%Vor%Hier sind die relevanten Bits des C ++ Standards, die beteiligt sind:
[dcl.init] / 16, bullet 6, sub-bullet 1: Wenn die Initialisierung eine direkte Initialisierung ist oder wenn es sich um eine Kopierinitialisierung handelt, bei der die cv-unqualifizierte Version des Quelltyps dieselbe Klasse wie oder eine abgeleitete Klasse von, die Klasse des Ziels, Konstruktoren werden berücksichtigt .... Wenn kein Konstruktor angewendet wird oder die Überladungsauflösung mehrdeutig ist, ist die Initialisierung nicht korrekt. [Hervorhebung hinzugefügt]
Mit anderen Worten, es spielt keine Rolle, ob eine Compileroptimierung für die Kopie geeignet ist, die Initialisierung ist schlecht, weil es keine anwendbaren Konstruktoren gibt. Nachdem Sie den Copy-Constructor veröffentlicht haben, gilt natürlich folgender Abschnitt:
[class.copy] / 31: Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung den Kopier- / Verschiebungsaufbau eines Klassenobjekts auslassen, selbst wenn der Kopier- / Verschiebungskonstruktor und / oder der Destruktor für das Objekt Nebeneffekte haben .... Diese Eliminierung von Kopier- / Verschiebevorgängen, die als Kopie Elision bezeichnet wird, ist unter den folgenden Umständen zulässig (die kombiniert werden können, um mehrere Kopien zu eliminieren):
bullet 3: Wenn ein temporäres Klassenobjekt, das nicht an eine Referenz (12.2) gebunden wurde, in ein Klassenobjekt mit dem gleichen cv-unqualifizierten Typ kopiert / verschoben wird, kann die Kopier- / Verschiebungsoperation weggelassen werden, indem die temporäres Objekt direkt in das Ziel der ausgelassenen Kopie / Verschiebung
Sie haben die sogenannte "Kopierinitialisierung" verwendet (definiert in [decl.init]
). Die definierte Bedeutung besteht darin, ein temporäres Objekt vom Typ X
mit dem Konstruktor int
zu konstruieren und dann x
mit dem Kopierkonstruktor aus dem temporären zu initialisieren.
Der Standard erlaubt jedoch auch eine Optimierung namens "copy constructor elision" (definiert in [class.copy]
) in diesem Fall. Wenn diese Optimierung angewendet wird, gibt es keine temporäre. x
wird mit dem int
-Konstruktor erstellt, als hätten Sie so genannte "direkte Initialisierung" X x(1);
.
Damit Sie nicht versehentlich Code schreiben, der kompiliert wird, wenn die Optimierung angewendet wird, aber nicht, wenn dies nicht der Fall ist, erfordert der Standard, dass der Kopierkonstruktor zugänglich sein muss, auch wenn er entfernt ist. Daher muss der Konstruktor öffentlich sein, obwohl er (mit dem Compiler und den Optionen, die Sie verwenden) nicht aufgerufen wird.
In C ++ werden 11 Move-Konstruktoren berücksichtigt und sind ebenfalls für Elision geeignet. Allerdings hat diese Klasse X
keinen Verschiebungskonstruktor, daher sind C ++ 11 und C ++ 03 für dieses Beispiel identisch.
Die Initialisierung wird vom Compiler optimiert auf:
%Vor%Dies ist eine Art von Kopie Elision, und ist durch den Standard erlaubt, obwohl es Nebenwirkungen entfernen kann, wie Sie gesehen haben.
Aus dem C ++ 03-Standardabschnitt 12.8:
Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung ausgelassen werden die Kopie Konstruktion eines Klassenobjekts, auch wenn der Kopierkonstruktor und / oder Destruktor für das Objekt haben Nebenwirkungen. In solchen Fällen Implementierung behandelt die Quelle und das Ziel der ausgelassenen Kopie Operation als einfach zwei verschiedene Möglichkeiten, auf dasselbe zu verweisen Objekt, und die Zerstörung dieses Objekts tritt bei der späteren der Zeiten, in denen die beiden Objekte ohne die Zerstörung zerstört worden wären Optimierung. 111) Diese Eliminierung von Kopiervorgängen ist erlaubt in der folgende Umstände (die kombiniert werden können, um mehrere zu eliminieren Kopien): - in einer Anweisung in einer Funktion mit einem Klassenrückgabetyp, wenn der Ausdruck der Name eines nichtflüchtigen automatischen Objekts ist mit demselben cv-unqualifizierten Typ wie der Funktion return type, der Die Kopieroperation kann weggelassen werden, indem das automatische Objekt konstruiert wird direkt in den Rückgabewert der Funktion - Wenn eine temporäre Klasse & gt; Objekt, das nicht an eine Referenz gebunden wurde (12.2) würde in ein Klassenobjekt mit demselben cv-unqualifizierten Typ, der Kopie, kopiert werden Die Operation kann weggelassen werden, indem das temporäre Objekt konstruiert wird direkt in das Ziel der ausgelassenen Kopie
Der zweite Fall ist, was wir hier haben.
Meine beste Vermutung ist, dass dies eine Compiler-Optimierung ist. Es gibt einen gültigen Pfad zum Deklarieren eines Objekts auf diese Weise, wenn Sie einen Kopierkonstruktor haben. Erwägen Sie dies explizit:
%Vor%Oder expliziter:
%Vor% Also, anstatt operator=
zu verwenden, weiß es, dass Sie versuchen, Ihr Objekt seit der Deklaration zu initialisieren. Im Wesentlichen ist der Compiler "schlau". Schließlich optimiert es dies wieder für diesen Schritt:
Nachdem der Compiler herausgefunden hat, was Sie zu tun versucht haben, wird dies zu einer Standardinitialisierung des Objekts.
BEARBEITEN
Beachten Sie die Vollständigkeit, wenn Sie Folgendes versuchen:
%Vor% Sie werden das Problem mit privatem operator=
sehen. Explizit ist es wichtig zu beachten, dass operator=
niemals tatsächlich in der ursprünglichen Initialisierungsfrage oben verwendet wird, obwohl =
im Code angezeigt wird.
Tags und Links c++ constructor oop