2 Stimmen

C++ Rückgabe nach Wert

Aus dem unten stehenden Code habe ich für die Klasse CA erwartet, dass folgendes aufgerufen wird

  1. Konstruktor, der das temporäre Objekt erzeugt, das von der Funktion zurückgegeben wird foo
  2. Kopierkonstruktor, um die Variable zu erstellen, die an die Variable übergeben wird a in der Hauptsache
  3. einen weiteren Kopierkonstruktor, der die a Variable aus dem von der Funktion zurückgegebenen Wert.

Warum ist das nicht der Fall? Das Ergebnis, das ich habe, ist einfach

A

Ich hatte zwar erwartet, dass

ABB

Es wird also nur der Konstruktor aufgerufen. Optimiert der Compiler etwas hinter den Kulissen oder habe ich ein C++-Konzept übersehen?

class CA{
public:
   CA(){ std::cout << "A"; }
   CA( const CA& ){ std::cout << "B"; }
   CA& operator=(const CA& ){ std::cout << "C";return *this; }
};

CA foo(){
      return CA();
}

int main(){
 CA a = foo();    
}

8voto

Luchian Grigore Punkte 244505

Optimiert der Compiler etwas hinter den Kulissen, oder habe ich ein C++-Konzept übersehen?

Genau richtig! Das nennt man Copy Elision. Schlagen Sie RVO und NRVO bei Google nach. Sie sollten auch die Dreierregel nachschlagen.

Das Eliminieren von Kopien ist die einzige Optimierung, die der Compiler durchführen darf und die das beobachtbare Verhalten beeinflusst. Aus diesem Grund sollten Sie wichtige Logik nicht im Kopierkonstruktor unterbringen.

0voto

AnT Punkte 300728

Es gibt mindestens zwei "Arten" von Optimierungen in C++.

  • Die erste Art sind spezifische Optimierungen, die ausdrücklich durch die Sprachspezifikation eingeführt werden.

  • Die zweite Art sind all die wilden und unvorhersehbaren Optimierungen, die Compiler unter der "als-ob"-Regel durchführen (d.h. der Compiler kann absolut alles tun, solange das beobachtbare Verhalten des Programms unverändert bleibt).

(Man könnte sagen, dass nur die zweite Art von Optimierungen wahr Optimierungen).

Was Sie hier sehen, ist eine Optimierung der ersten Art. Bei der Durchführung von mehrstufigen Kopiervorgängen hat die Sprachspezifikation den Compilern ausdrücklich erlaubt, temporäre Zwischenkopien zu eliminieren.

Darüber hinaus gehen C++03 und spätere Versionen der Sprachspezifikation noch einen Schritt weiter: Sie erlauben den Compilern ausdrücklich, die "Named Return Value Optimization" (NRVO) durchzuführen, die ein benanntes (nicht temporäres) Objekt tatsächlich eliminiert.

Beide reduzieren die Anzahl der Kopiervorgänge im Programm.

Solche Optimierungen zur Beseitigung von Kopien sind in C++ auch dann zulässig, wenn sie das beobachtbare Verhalten des Programms verändern, d.h. die Optimierungen der ersten Art können manchmal gegen die für die zweite Art geltenden Einschränkungen verstoßen. In Ihrem Fall, obwohl Sie E/A-Operationen in den Kopierkonstruktor eingefügt haben, ist es dem Compiler dennoch erlaubt, die Aufrufe dieses Konstruktors zu eliminieren.

Der Code, den Sie gepostet haben, erfordert keine NRVO. Ein guter C++98-Compiler sollte in der Lage sein, das von Ihnen beobachtete Ergebnis zu erzeugen. Wenn Sie sehen wollen, ob Ihr Compiler in solchen Fällen NRVO ausführt, können Sie Folgendes versuchen

CA foo(){
  Ca ca;
  return ca;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X