ProgrammierungC++ Entwickler

Was ist der Unterschied zwischen direkter und indirekter Objektinitialisierung in C++ und welche Konsequenzen kann dies bei der Arbeit mit eingebauten und benutzerdefinierten Typen haben?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

In C++ unterscheidet man zwischen direkter (direct) und indirekter (copy) Initialisierung von Objekten:

  • Direkte Initialisierung:

    MyClass obj(arg1, arg2); int x(5);

    Bei Klassen wird der entsprechende Konstruktor direkt aufgerufen.

  • Indirekte Initialisierung:

    MyClass obj = MyClass(arg1, arg2); int x = 5;

    Dies erstellt ein temporäres Objekt und kopiert (oder verschiebt) es dann (verwendet den Kopier- oder Verschiebekonstruktor).

Unterschiede:

  1. Für eingebaute Typen ist das Verhalten identisch. Für Klassen kann es unterschiedliche Aufrufe von Konstruktoren oder sogar verbotene Initialisierungen geben.
  2. Die Initialisierungsliste von Mitgliedern ist nicht immer äquivalent für verschiedene Initialisierungsmethoden aufgrund der Anforderungen des Compilers.
  3. Copy Elision (Optimierung des Compilers zur Vermeidung unnötiger Kopien) macht den Unterschied oft nichtig (aber nicht immer, insbesondere vor C++17).

Beispiel:

struct NonCopyable { NonCopyable(int) {} NonCopyable(const NonCopyable&) = delete; }; NonCopyable a(5); // OK: direkt NonCopyable b = NonCopyable(5); // OK mit Optimierung, Fehler vor C++17 ohne NonCopyable c = 5; // Fehler: kein Kopierkonstruktor vorhanden

Fangfrage

"Kann die copy-initialization mehr Konstruktoraufrufe verursachen als die direct-initialization, wenn C++11 verwendet wird und ein optimierender Compiler aktiviert ist?"

Antwort: Theoretisch – ja. Ohne Copy Elision erstellt die copy-initialization ein temporäres Objekt und ruft dann den Kopier- oder Verschiebekonstruktor auf. Die direct-initialization ruft immer nur den Hauptkonstruktor auf. Moderne Compiler mit aktivierter Optimierung (C++17 und höher) beseitigen jedoch diesen Unterschied durch garantierte Copy Elision.

Beispiele für echte Fehler aufgrund mangelnden Wissens über die Feinheiten des Themas


Geschichte

In einem Finanzprojekt wurde die copy-initialization mit einem temporären Objekt verwendet, während der benötigte Typ keinen Kopierkonstruktor hatte. Die Anwendung ließ sich auf älteren Compilern (vor C++17) nicht kompilieren, obwohl die direct-init funktionierte.


Geschichte

In einem Datenserialize-Utility gingen Programmierer davon aus, dass direct-init und copy-init äquivalent sind. Infolgedessen traten unnötige Kopien großer Strukturen auf und es kam zu Leistungsproblemen.


Geschichte

Bei der Initialisierung globaler Arrays benutzerdefinierter Objekte wurde indirekte Initialisierung verwendet. Fehler traten nur auf einer Plattform auf, auf der keine Copy Elision stattfand, und es gab implizite Aufrufe zusätzlicher Konstruktoren aufgrund von ABI-Eigenheiten.