17

Für dieses ProgrammC++ Kopierkonstruktor, Provisorien und kopieren Semantik

#include <iostream> 
using std::cout; 

struct C 
{ 
    C() { cout << "Default C called!\n"; } 
    C(const C &rhs) { cout << "CC called!\n"; } 
}; 

const C f() 
{ 
    cout << "Entered f()!\n"; 
    return C(); 
} 

int main() 
{ 
    C a = f(); 
    C b = a; 

    return 0; 
} 

der Ausgang I erhalten ist:

Entered f()! 
Default C called! 
CC called! 

Da f() wird durch Wert zurückgibt, sollte es eine vorübergehende Rückkehr. Wie T a = x; ist T a(x);, würde es nicht den Kopierkonstruktor für den Bau von a aufrufen, mit der vorübergehenden als Argument übergeben?

Antwort

14

Da f() nach Wert zurückgegeben wird, sollte es eine temporäre zurückgeben. Wie T a = x; ist T a(x);, würde es nicht den Kopierkonstruktor für den Bau von a aufrufen, mit der vorübergehenden als Argument übergeben?

Nachschlagen Rückgabewertoptimierung. Dies ist standardmäßig aktiviert. Wenn Sie Windows mit MSVC 2005+ verwenden, können Sie /Od verwenden, um dies auszuschalten und das gewünschte Ergebnis zu erhalten (oder -fno-elide-constructors bei GCC). Auch für MSVC siehe this Artikel.

12,8 Kopieren Klassenobjekte

Wenn bestimmte Kriterien erfüllt sind, eine Implementierung erlaubt ist, die Kopie Bau eines Klassenobjekts zu verzichten, auch wenn der Copykonstruktor und/oder destructor für das Objekt haben Seite Effekte. In solchen Fällen behandelt die Implementierung der Quelle und Ziel des Kopiervorgangs weggelassen als einfach zwei verschiedene Arten von auf das gleiche Objekt Bezug genommen wird, und die Zerstörung des Objekts erfolgt bei die später von der Zeit, als die beiden Objekte hätten ohne die Optimierung zerstört worden.115 Diese elision Kopier Operationen ist in den folgenden Umständen erlaubt (was kombiniert werden kann multiple Kopien zu eliminieren):

- in einer Return-Anweisung in einer Funktion mit einem Klasse Rückgabetyp, wenn der Ausdruck ist der Name ein nichtflüchtigen automatischen Objekt mit dem gleichen cv-unqualifizierten Typ wie der Funktion Rückgabetyp, kann der Kopiervorgang durch Konstruktion des automatische Objekts weggelassen wird direkt in die Funktion des Wieder Wert drehen - in einer Wurf-expression, wenn der Operand der Name ein nichtflüchtigen automatischen Objekts ist, der Kopiervorgang von dem Operanden an das Ausnahmeobjekt (15.1) kann durch Aufbau der automatischen weggelassen Objekt direkt in das Ausnahmeobjekt

- , wenn ein temporäres Klasse-Objekt, das auf eine Referenz wurde nicht gebunden (12.2) mit zu einem Klassenobjekt kopiert werden würde die gleiche cv-unqualifizierte Art, die Kopie Betrieb kann durchentfallenKonstruieren des temporäre Objekts direkt in das Ziel der weggelassen Kopie

- wenn die ausnahme Erklärung einer Ausnahme Handler (Klausel 15) erklärt, um ein Objekt desselben Typs (mit Ausnahme von cv-Qualifikation) als Ausnahme Objekt (15.1), kann der Kopiervorgang durch Behandlung der Ausnahme-Deklaration als Alias ​​für das Ausnahmeobjekt, wenn die Bedeutung von das Programm unverändert sein wird außer für die Ausführung der Konstrukteure entfallen und Destruktoren für das von deklarierte Objekt die Ausnahmedeklaration.

Hinweis: Der Schwerpunkt Mine

+0

Ich benutze GCC, und mit '-fno-elide-constructors' zeigte es genau, was unter der Haube passiert! Manchmal verwirren diese Optimierungen den Lernenden sehr. Allerdings stimme ich zu, dass sie standardmäßig aktiviert sein sollten, da der Build einer uninformierten Person wieder standardmäßig optimiert wird. – legends2k

+0

@ Legends2k: RVO ist zu nützlich, um den Launen der Benutzer überlassen zu werden.Außerdem ist dies einer der wenigen Fälle, in denen der Standard eine Optimierung ermöglicht. Das stärkt wieder, warum es so weiter geht. Beachten Sie jedoch, dass dies für andere Optimierungen im Allgemeinen nicht gilt. – dirkgently

+0

Einverstanden, Punkt genommen. – legends2k

4

Dies ist ein Beispiel für Return Value Optimization (RVO) Funktionen, die Ihr Compiler unterstützt.

Ein Kopierkonstruktor könnte nicht aufgerufen werden, wenn Sie nach Wert zurückgeben.

Verwenden Sie die Option -fno-elide-constructors bei GCC, um diese Funktion auszuschalten.

+0

+1 für die schnelle Antwort! – legends2k

2

Ich glaube, es return value optimization genannt wird.

Ich gehe davon aus, wenn f() kehrt C das Objekt Objekt in dem Stapelspeicher der rufenden Methode zugewiesen werden daher keine Kopie erforderlich C a zu initialisieren. Dies ist Ihre default C called.

C b = a 

Dies verursacht einen Kopierkonstruktor daher Ihre CC called.

Btw, das Beispiel in Wiki sieht Ihrem Code ähnlich.

+0

+1 für den Wiki-Link. Hoppla! Sogar die Namensgebung sieht ähnlich aus, aber ich schwöre, dass ich nach dem Lesen nicht gepostet habe, ich lese _Thinking in C++ _ :) – legends2k