Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden?

Lesezeit: 8 Minuten

Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
paxos1977

Ich verwende gerne Member-Initialisierungslisten mit meinen Konstruktoren … aber ich habe die Gründe dafür schon lange vergessen …

Verwenden Sie Member-Initialisierungslisten in Ihren Konstruktoren? Wenn ja warum? Wenn nein, warum nicht?

Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
Adam Rosenfeld

Für die Mitglieder der POD-Klasse macht es keinen Unterschied, es ist nur eine Frage des Stils. Für Klassenmember, die Klassen sind, wird dann ein unnötiger Aufruf eines Standardkonstruktors vermieden. Erwägen:

class A
{
public:
    A() { x = 0; }
    A(int x_) { x = x_; }
    int x;
};

class B
{
public:
    B()
    {
        a.x = 3;
    }
private:
    A a;
};

In diesem Fall ist der Konstruktor für B ruft den Standardkonstruktor für auf Aund dann initialisieren a.x zu 3. Ein besserer Weg wäre z B‘s-Konstruktor, der direkt aufgerufen werden soll A‘s Konstruktor in der Initialisierungsliste:

B()
  : a(3)
{
}

Dies würde nur anrufen A‘S A(int) Konstruktor und nicht sein Standardkonstruktor. In diesem Beispiel ist der Unterschied vernachlässigbar, aber stellen Sie sich das vor ADer Standardkonstruktor von hat mehr getan, wie z. B. das Zuweisen von Speicher oder das Öffnen von Dateien. Sie würden das nicht unnötig tun wollen.

Wenn eine Klasse keinen Standardkonstruktor hat oder Sie einen haben const Mitgliedsvariable, du Muss Verwenden Sie eine Initialisierungsliste:

class A
{
public:
    A(int x_) { x = x_; }
    int x;
};

class B
{
public:
    B() : a(3), y(2)  // 'a' and 'y' MUST be initialized in an initializer list;
    {                 // it is an error not to do so
    }
private:
    A a;
    const int y;
};

  • Ein Muss ist auch bei wichtigen Hinweisen

    – 4pie0

    6. Mai 2014 um 12:38 Uhr

  • Warum nicht “a(3);” verwenden? oder “a = A(3);” im Körper des Standardkonstruktors von B?

    – Sergej

    6. März 2015 um 10:07 Uhr

  • Können Sie erklären, was Sie mit POD meinen?

    – Jonas Stein

    19. November 2015 um 11:12 Uhr

  • @JonasStein POD ist ein klar definierter Satz von Regeln, die sich auf einfache Datenstrukturen (und nicht auf vollständige Klassen) beziehen. Weitere Informationen finden Sie in den häufig gestellten Fragen: stackoverflow.com/questions/146452/what-are-pod-types-in-c

    – Affe0506

    28. März 2016 um 4:02 Uhr

  • @Sergey, der Standardkonstruktor von A würde immer noch aufgerufen werden.

    – Wassilis

    2. Mai 2017 um 18:24 Uhr

1647271210 609 Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
Naveen

Abgesehen von den oben erwähnten Leistungsgründen haben Sie keine andere Wahl, als Initialisierungslisten zu verwenden, wenn Ihre Klasse Verweise auf Objekte speichert, die als Konstruktorparameter übergeben werden, oder Ihre Klasse über konstante Variablen verfügt.

  • Dasselbe gilt für const-Mitglieder, glaube ich.

    – Richard Corden

    29. Mai 2009 um 16:44 Uhr

  • ja, Zuweisung kann nicht verwendet werden, um die konstanten Variablen zu ändern, daher muss sie initialisiert werden.

    – Hareen Laks

    14. April 2018 um 13:53 Uhr

1647271211 359 Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
Yuvi

  1. Initialisierung der Basisklasse

Ein wichtiger Grund für die Verwendung der Konstruktor-Initialisierungsliste, der hier nicht in den Antworten erwähnt wird, ist die Initialisierung der Basisklasse.

Gemäß der Konstruktionsreihenfolge sollte die Basisklasse vor der untergeordneten Klasse erstellt werden. Ohne Konstruktor-Initialisierungsliste ist dies möglich, wenn Ihre Basisklasse über einen Standardkonstruktor verfügt, der aufgerufen wird, bevor der Konstruktor der untergeordneten Klasse eingegeben wird.

Wenn Ihre Basisklasse jedoch nur über einen parametrisierten Konstruktor verfügt, müssen Sie die Konstruktor-Initialisierungsliste verwenden, um sicherzustellen, dass Ihre Basisklasse vor der untergeordneten Klasse initialisiert wird.

  1. Initialisierung von Unterobjekten, die nur parametrisierte Konstruktoren haben

  2. Effizienz

Mit der Konstruktor-Initialisierungsliste initialisieren Sie Ihre Datenelemente auf den genauen Zustand, den Sie in Ihrem Code benötigen, anstatt sie zuerst auf ihren Standardzustand zu initialisieren und dann ihren Zustand auf den zu ändern, den Sie in Ihrem Code benötigen.

  1. Initialisieren von nicht statischen konstanten Datenelementen

Wenn nicht statische konstante Datenmember in Ihrer Klasse Standardkonstruktoren haben und Sie keine Konstruktor-Initialisierungsliste verwenden, können Sie sie nicht in den beabsichtigten Zustand initialisieren, da sie in ihren Standardzustand initialisiert werden.

  1. Initialisierung von Referenzdatenelementen

Referenzdatenmember müssen initialisiert werden, wenn der Compiler in den Konstruktor eintritt, da Referenzen nicht einfach deklariert und später initialisiert werden können. Dies ist nur mit Konstruktorinitialisiererliste möglich.

1647271211 282 Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
mloskot

Neben den Leistungsproblemen gibt es noch ein weiteres sehr wichtiges, das ich Code-Wartbarkeit und -Erweiterbarkeit nennen würde.

Wenn ein T ist POD und Sie starten lieber die Initialisierungsliste, dann wenn einmal T in einen Nicht-POD-Typ ändern, müssen Sie nichts um die Initialisierung herum ändern, um unnötige Konstruktoraufrufe zu vermeiden, da sie bereits optimiert ist.

Wenn Typ T hat einen Standardkonstruktor und einen oder mehrere benutzerdefinierte Konstruktoren und wenn Sie sich einmal entscheiden, den Standardkonstruktor zu entfernen oder auszublenden, müssen Sie den Code Ihrer benutzerdefinierten Konstruktoren nicht aktualisieren, wenn die Initialisierungsliste verwendet wurde, da dies bereits der Fall ist richtig umgesetzt.

Das gleiche mit const Mitglieder oder Referenzmitglieder, sagen wir zunächst T ist wie folgt definiert:

struct T
{
    T() { a = 5; }
private:
    int a;
};

Als nächstes entscheidest du dich, dich zu qualifizieren a als constwenn Sie die Initialisierungsliste von Anfang an verwenden würden, dann wäre dies eine einzelne Zeilenänderung, aber mit der T wie oben definiert, muss auch die Konstruktordefinition ausgegraben werden, um die Zuweisung zu entfernen:

struct T
{
    T() : a(5) {} // 2. that requires changes here too
private:
    const int a; // 1. one line change
};

Es ist kein Geheimnis, dass die Wartung viel einfacher und weniger fehleranfällig ist, wenn der Code nicht von einem „Code-Affen“ geschrieben wurde, sondern von einem Ingenieur, der Entscheidungen auf der Grundlage gründlicher Überlegungen darüber trifft, was er tut.

Bevor der Hauptteil des Konstruktors ausgeführt wird, werden alle Konstruktoren für seine übergeordnete Klasse und dann für seine Felder aufgerufen. Standardmäßig werden die Konstruktoren ohne Argumente aufgerufen. Mit Initialisierungslisten können Sie auswählen, welcher Konstruktor aufgerufen wird und welche Argumente dieser Konstruktor erhält.

Wenn Sie eine Referenz oder ein konstantes Feld haben oder wenn eine der verwendeten Klassen keinen Standardkonstruktor hat, müssen Sie eine Initialisierungsliste verwenden.

Schwerwiegender VC Fehler LNK1168 Dateinameexe kann nicht zum Schreiben geoffnet werden
Amal K

// Without Initializer List
class MyClass {
    Type variable;
public:
    MyClass(Type a) {  // Assume that Type is an already
                     // declared class and it has appropriate 
                     // constructors and operators
        variable = a;
    }
};
 

Hier führt der Compiler die folgenden Schritte aus, um ein Objekt des Typs zu erstellen MyClass:

  1. TypeDer Konstruktor von wird zuerst aufgerufen für „a“.
  2. Der Zuweisungsoperator von „Type“ wird im Körper von aufgerufen MyClass() Konstruktor zuzuweisen.
variable = a;
  1. Und dann endlich der Destruktor von „Type” wird gerufen für “a“, da es außerhalb des Geltungsbereichs liegt.

Betrachten Sie nun den gleichen Code mit MyClass() Konstruktor mit einer Initialisierungsliste:

    // With Initializer List
    class MyClass {
    Type variable;
    public:
    MyClass(Type a):variable(a) {   // Assume that Type is an already
                     // declared class and it has appropriate
                     // constructors and operators
    }
    };
 

Bei der Initializer List folgt der Compiler folgenden Schritten:

  1. Kopierkonstruktor von „Type” Klasse wird aufgerufen, um zu initialisieren: variable(a). Die Argumente in der Initialisierungsliste werden verwendet, um das Konstrukt „variable” direkt.

  2. Destruktor von „Type” wird gerufen für “a“, da es außerhalb des Geltungsbereichs liegt.

1647271212 264 Warum sollte ich lieber Mitgliedsinitialisierungslisten verwenden
Eswaran Pandi

Syntax:

  class Sample
  {
     public:
         int Sam_x;
         int Sam_y;

     Sample(): Sam_x(1), Sam_y(2)     /* Classname: Initialization List */
     {
           // Constructor body
     }
  };

Notwendigkeit der Initialisierungsliste:

 class Sample
 {
     public:
         int Sam_x;
         int Sam_y;

     Sample()     */* Object and variables are created - i.e.:declaration of variables */*
     { // Constructor body starts 

         Sam_x = 1;      */* Defining a value to the variable */* 
         Sam_y = 2;

     } // Constructor body ends
  };

im obigen Programm, wenn der Konstruktor der Klasse ausgeführt wird, Sam_x und Sam_y werden erstellt. Dann werden im Konstruktorkörper diese Mitgliedsdatenvariablen definiert.

Anwendungsfälle:

  1. Konstante und Referenzvariablen in einer Klasse

In C Variablen Muss während der Erstellung definiert werden. Auf die gleiche Weise müssen wir in C++ die Variablen Const und Reference während der Objekterstellung initialisieren, indem wir die Initialisierungsliste verwenden. Wenn wir nach der Objekterstellung initialisieren (innerhalb des Konstruktorkörpers), erhalten wir einen Kompilierzeitfehler.

  1. Mitgliedsobjekte der Klasse Sample1 (Basis) ohne Standardkonstruktor

     class Sample1 
     {
         int i;
         public:
         Sample1 (int temp)
         {
            i = temp;
         }
     };
    
      // Class Sample2 contains object of Sample1 
     class Sample2
     {
      Sample1  a;
      public:
      Sample2 (int x): a(x)      /* Initializer list must be used */
      {
    
      }
     };
    

Beim Erstellen eines Objekts für die abgeleitete Klasse, das den abgeleiteten Klassenkonstruktor intern aufruft und den Basisklassenkonstruktor aufruft (Standard). Wenn die Basisklasse keinen Standardkonstruktor hat, erhält der Benutzer einen Kompilierzeitfehler. Um dies zu vermeiden, müssen wir beides haben

 1. Default constructor of Sample1 class
 2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
  1. Der Parametername des Klassenkonstruktors und das Datenelement einer Klasse sind gleich:

     class Sample3 {
        int i;         /* Member variable name : i */  
        public:
        Sample3 (int i)    /* Local variable name : i */ 
        {
            i = i;
            print(i);   /* Local variable: Prints the correct value which we passed in constructor */
        }
        int getI() const 
        { 
             print(i);    /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
             return i; 
        }
     };
    

Wie wir alle wissen, hat die lokale Variable die höchste Priorität und dann die globale Variable, wenn beide Variablen den gleichen Namen haben. In diesem Fall berücksichtigt das Programm den “i”-Wert {sowohl linke als auch rechte Seitenvariable. dh: i = i} als lokale Variable im Sample3()-Konstruktor und Klassenmitgliedsvariable (i) wurde überschrieben. Um dies zu vermeiden, müssen wir beides verwenden

  1. Initialization list 
  2. this operator.

1002100cookie-checkWarum sollte ich lieber Mitgliedsinitialisierungslisten verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy