Bedeutung der Standardinitialisierung in C++11 geändert?

Lesezeit: 5 Minuten

Bedeutung der Standardinitialisierung in C11 geandert
Adrian McCarthy

C++2003 8.5/5 sagt:

Zu default-initialisieren ein Objekt vom Typ T bedeutet:

— wenn T ein Nicht-POD-Klassentyp ist (Klausel 9), wird der Standardkonstruktor für T aufgerufen (und die Initialisierung ist falsch formatiert, wenn T keinen zugänglichen Standardkonstruktor hat);

— Wenn T ein Array-Typ ist, wird jedes Element standardmäßig initialisiert;

— andernfalls ist das Objekt nullinitialisiert.

[Emphasis added.]

Der C++2011-Standard änderte diesen letzten Punkt in

– ansonsten, es wird keine Initialisierung durchgeführt.

Dies scheint für einige Programme eine bahnbrechende Änderung zu sein. War dies beabsichtigt?

Bearbeiten

Hier ist ein Code, um diese Frage zu motivieren:

class Foo {
  public:
    Foo() : m_values() {}

    int m_values[3];
};

Vor C++11 dachte ich, die explizite Erwähnung von m_values im Standardkonstruktor würde default-initialisieren dieses Array. Und da die Elemente des Arrays skalar sind, habe ich erwartet, dass die Werte alle auf 0 gesetzt wurden.

In C++11 scheint es keine Garantie mehr dafür zu geben, dass dies geschieht. Aber vielleicht, wie Mooing Duck in den Kommentaren hervorhob, handelt es sich vielleicht nicht mehr um eine Standardinitialisierung, sondern um eine andere Form, die das erwartete Verhalten beibehält. Zitate willkommen.

  • die Objekte werden nicht initialisiert. es handelt sich also um NICHT INITIALISIERTE OBJEKTE.

    – Victor

    6. März ’14 um 18:42

  • @Victor: Er ist sich dessen bewusst. Sein Punkt ist, dass der Wechsel von initialisiert zu nicht initialisiert ein Breaking Change ist.

    – Muhende Ente

    6. März ’14 um 18:47

  • Ich erinnere mich, gehört zu haben, dass C++03 nicht “Wert-Initialisierung” vs. “Standard-Initialisierung” vs. “Null-Initialisierung” oder so etwas hatte. Ist es möglich, dass Dinge, die zuvor standardmäßig initialisiert wurden, jetzt mit Null initialisiert sind, was dies zu einer nicht unterbrechungsfreien Änderung macht?

    – Muhende Ente

    6. März ’14 um 18:48


  • m_values sollte mit einem Wert initialisiert werden, da er Teil der Memberinitialisiererliste mit leeren Klammern ist.

    Benutzer1508519

    6. März ’14 um 19:32

Die endgültigen Effekte sind fast die gleichen. In C++03 ist die Verwendung von default-initialisieren war auf Nicht-POD-Klassentypen beschränkt, sodass der letzte Punkt nie zutraf. In C++11 vereinfacht der Standard den Wortlaut, indem er die Bedingung bezüglich der Verwendung der Standard-Initialisierung beseitigt und die Definition der Standard-Initialisierung ändert, um alle Fälle so abzudecken, dass sie dem entsprechen, was zuvor passiert ist.

  • Insbesondere C++03 8.5/9: Wenn für ein Objekt kein Initialisierer angegeben ist und das Objekt vom (möglicherweise CV-qualifizierten) Nicht-POD-Klassentyp (oder Array davon) ist, soll das Objekt standardmäßig initialisiert werden; wenn das Objekt vom const-qualifizierten Typ ist, muss der zugrunde liegende Klassentyp einen vom Benutzer deklarierten Standardkonstruktor haben. Andernfalls, wenn für ein nicht statisches Objekt kein Initialisierer angegeben ist, haben das Objekt und seine Unterobjekte, falls vorhanden, einen unbestimmten Anfangswert; Wenn das Objekt oder eines seiner Unterobjekte vom Typ const ist, ist das Programm falsch formatiert.

    – Casey

    6. März ’14 um 20:11

  • vs. C++11 8.5/11: Wenn für ein Objekt kein Initialisierer angegeben ist, wird das Objekt standardmäßig initialisiert; Wenn keine Initialisierung durchgeführt wird, hat ein Objekt mit automatischer oder dynamischer Speicherdauer einen unbestimmten Wert.

    – Casey

    6. März ’14 um 20:12 Uhr

  • Ich verstehe diese Antwort nicht ganz. Sagst du das seit dem m_values Array im Beispiel ist POD, dass die Standard-Initialisierung nie angewendet wurde, nicht einmal in C++03? Könntest Du das erläutern? Wenn ich a konstruiere Foo wie oben gezeigt, werden die Werte in m_values 0 oder unbestimmt sein?

    – Adrian McCarthy

    7. März ’14 um 0:46

  • @JamesKanze: Ihre Antwort sieht für viele hilfreich aus, aber ich habe immer noch die Fragen von meinem vorherigen Kommentar. Wenn Sie diese klären könnten, würde ich das gerne annehmen.

    – Adrian McCarthy

    19. März ’14 um 17:23

  • @AdrianMcCarthy: Wegen der expliziten m_values() im Konstruktor wird das Array in keiner C++-Version standardmäßig initialisiert; es wird mit einem Wert initialisiert (was in C++03 und 11 gleich ist). Wenn dies nicht vorhanden ist, muss das Array in C++03 nicht initialisiert und in C++11 standardmäßig initialisiert werden.

    – Chris Dodd

    15. August ’17 um 17:43

Gemäß cppreference.com (weil es eine freundlichere Sprache verwendet als der Standard):

Die Standardinitialisierung wird in drei Situationen durchgeführt:

3) wenn eine Basisklasse oder ein nicht statischer Datenmember in einer Konstruktorinitialisiererliste nicht erwähnt wird und dieser Konstruktor aufgerufen wird.

Die Wertinitialisierung wird in drei Situationen durchgeführt:

3,7) wenn ein nicht statischer Datenmember oder eine Basisklasse mit einem Memberinitialisierer mit einem leeren Klammerpaar initialisiert wird or braces (since C++11)

Beachten Sie, dass der C++11-Teil zum gehört or braces, nicht mit dem ganzen Absatz.

Und:

Ein Objekt vom Typ T wertinitialisieren bedeutet:
— Wenn T ein Array-Typ ist, wird jedes Element wertinitialisiert;
— andernfalls ist das Objekt nullinitialisiert

Also in C++11 Default-Initialisierung initialisiert Mitglieder nicht mit Null, aber Wert-Initialisierung tut.

Bedeutung der Standardinitialisierung in C11 geandert
MWid

Genau genommen ist die Definition von default-initialisieren hat sich von C++03 auf C++11 geändert. Aber man muss auch berücksichtigen, dass die Situationen, in denen ein Objekt _default-initialize_d ist, geändert werden:

§8.5p9 C++03 besagt:

Wenn für ein Objekt kein Initialisierer angegeben ist und das Objekt vom (möglicherweise CV-qualifizierten) Nicht-POD-Klassentyp (oder Array davon) ist, soll das Objekt standardmäßig initialisiert werden; wenn das Objekt vom const-qualifizierten Typ ist, muss der zugrunde liegende Klassentyp einen vom Benutzer deklarierten Standardkonstruktor haben. Andernfalls, wenn für ein nicht statisches Objekt kein Initialisierer angegeben ist, haben das Objekt und seine Unterobjekte, falls vorhanden, einen unbestimmten Anfangswert; Wenn das Objekt oder eines seiner Unterobjekte vom Typ const ist, ist das Programm falsch formatiert.

§8.5p11 C++11 besagt:

Wenn für ein Objekt kein Initialisierer angegeben ist, wird das Objekt standardmäßig initialisiert; Wenn keine Initialisierung durchgeführt wird, hat ein Objekt mit automatischer oder dynamischer Speicherdauer einen unbestimmten Wert.

Wie @JamesKanze bereits erwähnt hat, Default-Initialisierung wird in C++03 ausgeführt, wenn kein Initialisierer für ein Objekt des Nicht-POD-Klassentyps angegeben ist. In C++11 ist ein Objekt (beliebigen Typs) default-initialisiert wenn kein Initialisierer angegeben ist. Aufgrund dieser Änderung ist die Definition von default-initialisieren musste auch geändert werden, um mit C++03 kompatibel zu sein.


Dein Beispiel hat nichts damit zu tun Default-Initialisierung. Es war immer so, dass ein Objekt, dessen Initialisierer ein leerer Satz von Klammern ist, wertinitialisiert.

.

234590cookie-checkBedeutung der Standardinitialisierung in C++11 geändert?

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

Privacy policy