Namensräume
Varianten
Aktionen

copy elision

Aus cppreference.com
< cpp‎ | language
 
 
Sprache C + +
Allgemeine Themen
Original:
General topics
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Flusskontrolle
Original:
Flow control
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Bedingte Ausführung Aussagen
Original:
Conditional execution statements
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Iterationsanweisungen
Original:
Iteration statements
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Gehe Aussagen
Original:
Jump statements
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Funktionen
Original:
Functions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Funktion Erklärung
Lambda-Funktion Erklärung
Funktions-Template
inline-Spezifizierer
Exception-Spezifikationen (veraltet)
noexcept Spezifizierer (C++11)
Ausnahmen
Original:
Exceptions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Namespaces
Original:
Namespaces
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Types
Original:
Types
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
decltype specifier (C++11)
Specifiers
Original:
Specifiers
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
cv Planer
Lagerdauer Planer
constexpr Spezifizierer (C++11)
auto Spezifizierer (C++11)
alignas Spezifizierer (C++11)
Initialisierung
Original:
Initialization
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Literale
Original:
Literals
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Expressions
Original:
Expressions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
alternative Darstellungen
Utilities
Original:
Utilities
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Types
Original:
Types
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
typedef declaration
Typ Aliasdeklaration (C++11)
Attribute (C++11)
Wirft
Original:
Casts
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
impliziten Konvertierungen
const_cast conversion
static_cast conversion
dynamic_cast conversion
reinterpret_cast conversion
C-Stil und funktionale Besetzung
Speicherzuweisung
Original:
Memory allocation
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Classes
Original:
Classes
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Class-spezifische Funktion Eigenschaften
Original:
Class-specific function properties
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
explizit (C++11)
statisch
Besondere Member-Funktionen
Original:
Special member functions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Templates
Original:
Templates
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Klassen-Template
Funktions-Template
Template-Spezialisierung
Parameter Packs (C++11)
Verschiedenes
Original:
Miscellaneous
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
Inline Montage
 

optimiert die Copy- und Move- (seit C++11)Konstruktoren weg und führt so zu einer kopierfreien Pass-by-Value-Semantik.

Inhaltsverzeichnis

[Bearbeiten] Erklärung

Unter folgenden Umständen müssen Kompiler die Copy- und Move-Konstruktoren der Klassenobjekte wegoptimieren, auch wenn der Copy-Konstruktor, der Move-Konstruktor oder der Destruktor sichtbare Nebenwirkungen besitzt.

  • Während der Initialisierung wird der Initialisierungausdruck direkt zur Initialisierung des Zielobjektes benutzt, falls er ein prvalue ist und der Quelltyp ohne cv-Qualifikationen derselbe Typ wie der Zieltyp ist:
T x = T(T(T())); // nur einmaliger Aufruf des Default-Konstruktors von T, um x zu initialiseren
  • Innerhalb des Aufrufes einer Funktion, falls der Operand einer Rückgabeanweisung ein prvalue ist und dessen Typ derselbe ist wie der Rückgabetyp.
T f() { return T{}; }
T x = f();         // nur einmaliger Aufruf des Default-Konstruktors von T, um x zu initialiseren
T* p = new T(f()); // nur einmaliger Aufruf des Default-Konstruktors von T, um *p zu initialiseren
(seit C++17)

Unter folgenden Umständen ist es Kompilern gestattet, Copy- und Move- (seit C++11)Konstruktoren von Klassenobjekten wegzuoptimieren, auch wenn der Copy-Konstruktor, der Move-Konstruktor (seit C++11) oder Destruktor sichtbare Nebenwirkungen hat.

  • Falls eine Funktion einen Klassentyp als Wert zurückgibt und die Return-Anweisung aus dem Name eines nichtflüchtigen Objektes mit automatischer Speicherdauer besteht, das weder ein Aufrufparameter der Funktion noch der Parameter einer Catch-Klausel ist, und unter Nichtberücksichtigung der cv-Qualifikation vom selben Typ wie der Rückgabetyp der Funktion ist, so wird die Kopie bzw. das Verschieben (seit C++11) unterlassen. Die lokale Variable wird direkt an der Speicherstelle erzeugt, zu der der Rückgabewert andernfalls kopiert bzw. verschoben (seit C++11) werden würde. Diese Variante der copy elision wird als NRVO (Named Return Value Optimization) bezeichnet.
  • Falls eine unbenannte, temporäre und nicht referenzierte Variable in ein Objekt unter Nichtberücksichtigung der cv-Qualifikation selben Types kopiert bzw. verschoben (seit C++11) werden würde, so wird das Kopieren bzw. Verschieben (seit C++11) unterlassen. Bei der Erzeugung der temporären Variable wird diese direkt im Speicherbereich der Variable, in die es anderenfalls kopiert bzw. verschoben (seit C++11) werden würde, erzeugt. Falls die unbenannte, temporäre Variable das Argument einer Rückgabeanweisung ist, so wird diese Variante der copy elision als RVO (Return Value Optimization) bezeichnet.
(bis C++17)
  • Falls in einem Throw-Ausdruck der Operand der Name eines nichtflüchtigen Objektes mit automatischer Speicherdauer ist, welches weder ein Aufrufparameter der Funktion noch der Parameter einer Catch-Klausel ist, und dessen Lebensdauer sich auf den innersten Try-Block, falls vorhanden, beschränkt, so wird das Kopieren bzw. Verschieben (seit C++11) unterlassen. Bei Erzeugen des lokalen Objekts wird es direkt im Speicherbereich erzeugt, in den es anderenfalls kopiert bzw. verschoben (seit C++11) werden würde.
(seit C++11)
  • Während der Behandling einer Ausnahme wird das Kopieren unterlassen, falls das Argument der Catch-Anweisung unter Nichtberücksichtigung der cv-Qualifikation vom selben Typ wie das geworfene Ausnahmeobjekt ist. In Rumpf der Catch-Anweisung wird das geworfene Ausnahmeobjekt direkt benutzt wie es auch beim Fangen einer Referenz geschehen würde. Diese Optimierung wird nicht vorgenommen, falls diese das beobachtbare Verhalten des Programmes aus einem anderen Grund als dem Auslassen des Copy-Konstruktors oder Destruktors des Argumentes der Catch-Anweisung verändert. Als Beispiel sei hier die Änderung an dem Argument der Catch-Anweisung und anschließendes Weiterreichen der Ausnahme genannt.
(seit C++11)

Falls das Kopieren bzw. Verschieben (seit C++11) unterlassen wird, werden die Quelle und das Ziel der nicht durchgeführten Kopieroperation (bis C + +11) Kopier- bzw. Verschiebeoperation (seit C++11) durch den Kompiler einfach als zwei Zugriffsmöglichketen auf dasselbe Objekt behandelt. Die Zerstörung des Objektes durch einen einzigen Destruktoraufruf erfolgt dann zum Zeitpunkt, wenn das Letzte der zwei Objekte ohne diese Optimierung zerstört worden wäre. (except that, if the parameter of the selected constructor is an rvalue reference to object type, the destruction occurs when the target would have been destroyed) (seit C++17).

Das Auslassungen der Kopieroperation (bis C + +11) Kopier- bzw. Verschiebeoperation (seit C++11) darf beliebig verkettet werden.

  • In konstanten Ausdrücken und Initialization von Konstanten ist das Entfernen jeglicher Kopie- bzw. Verschiebeoperation garantiert (siehe hierzu: post-C++14 defect report CWG 2022):
struct A {
    void *p;
    constexpr A(): p(this) {}
};
 
constexpr A g() {
  A a;
  return a;
}
 
constexpr A a;        // a.p points to a
constexpr A b = g();  // b.p points to b (NRVO guaranteed)
 
void g() {
  A c = g();          // c.p may point to c or to an ephemeral temporary
}
(seit C++14)

[Bearbeiten] Anmerkungen

Copy elision ist die einzige erlaubte Form der Optimierung (bis C++14)eine der beiden erlaubten Formen der Optimierung (neben allocation elision and extension) (seit C++14), die beobachtbare Nebenwirkungen ändern können. Da nicht alle Kompiler copy elison in jeder erlaubten Situation benutzen (z.B. ohne Optimierung), sind Programme, die auf den Nebenwirkungen von Copy- bzw. Move- (seit C++11)Konstruktoren und Destruktoren angewiesen sind, nicht ohne weiteres portierbar.

Falls copy elision benutzt wird, obwohl sie nicht garantiert ist, (seit C++17) und der Copy- bzw. Move- (seit C++11)Konstruktor nicht aufgerufen wird, muß er jedoch vorhanden und aufrufbar sein als ob keine Optimierung stattfinden würde. Andernfalls ist das Programm nicht regelkonform.

Falls der Kompiler innerhalb einer Rückgabeanweisung oder eines Throw-Ausdrucks keine copy elision durchführen kann, obwohl die Bedingungen für diese erfüllt sind oder sein würden, so versucht der Kompiler mit der Ausnahme, daß die Quelle ein Funktionsparameter ist, den Move-Konstruktor zu benutzen, auch wenn das Objekt durch einen lvalue beschrieben wird (siehe hierzu return statement).

(seit C++11)

[Bearbeiten] Beispiele

#include <iostream>
#include <vector>
 
struct Noisy
{
    Noisy() { std::cout << "constructed\n"; }
    Noisy(const Noisy&) { std::cout << "copy-constructed\n"; }
    Noisy(Noisy&&) { std::cout << "move-constructed\n"; }
    ~Noisy() { std::cout << "destructed\n"; }
};
 
std::vector<Noisy> f()
{
    std::vector<Noisy> v = std::vector<Noisy>(3); // copy elision: Initialisierung von v
                                                  // aus temporärem Objekt
                                                  // (garantiert seit C++17)
    return v; // NRVO: von v ins unbenamte, temporäe Rückgabeobjekt (nicht garantiert)
    }         //       oder Benutzung des Move-Konstruktor, falls die Optimierung nicht verwendet wird.
 
void g(std::vector<Noisy> arg)
{
    std::cout << "arg.size() = " << arg.size() << '\n';
}
 
int main()
{
    std::vector<Noisy> v = f(); // copy elision: Initialisierung von v
                                // aus unbenamten, temporären Rückgabeobjekt von f()
				// (garantiert seit C++17)
    g(f());                     // copy elision: Initialiserung des Parameters von g()
                                // aus unbenamten, temporären Rückgabeobjekt von f()
                                // (garantiert seit C++17)
}

Possible output:

constructed
constructed
constructed
constructed
constructed
constructed
arg.size() = 3
destructed
destructed
destructed
destructed
destructed
destructed


[Bearbeiten] Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte werden nachträglich angewandt auf schon veröffentlichte C++-Standards.

DR angewandt auf Verhalten im Standard korrigiertes Verhalten
CWG 2022 C++14 copy elision war nur optional in konstanten Ausdrücken Nun ist copy elision zwingend erforderlich.

[Bearbeiten] Verweise