Domyślny inicjalizator dla członka (default member initializer) — konstrukcja C++11, pozwalająca na deklarację wartości domyślnych bezpośrednio przy deklaracji zmiennych-członków klasy. Możliwość ta często bywa mylona z innymi sposobami inicjalizacji danych.
Wczesna wersja C++ nie pozwalała na inicjalizację członków bezpośrednio przy deklaracji; wartości przypisywano tylko w konstruktorze (w ciele lub w liście inicjalizacji). Wprowadzenie domyślnych inicjalizatorów dla członków (C++11) poprawiło czytelność i zmniejszyło ryzyko błędów związanych z nieokreśloną inicjalizacją.
Jeśli pola nie są jawnie zainicjalizowane, zawierają "śmieciowe" (nieokreślone) wartości. Przypisanie wewnątrz konstruktora jest mniej efektywne niż lista inicjalizacji, a ignorowanie domyślnych inicjalizatorów dla członków utrudnia rozszerzanie klas i tworzenie nowych konstruktorów.
Używaj domyślnych inicjalizatorów dla prostych wartości, a w przypadku bardziej złożonych sytuacji (szczególnie jeśli potrzebna jest zależna lub niestandardowa wartość) — listy inicjalizacji konstruktora.
Przykład kodu:
class Widget { int x = 42; // domyślny inicjalizator dla członka std::string name = "default"; // domyślny inicjalizator dla członka public: Widget() = default; // x=42, name="default" Widget(int xx) : x(xx), name("new") {}// x=xx, name="new" };
Kluczowe cechy:
Czy domyślny inicjalizator dla członka zostanie zastosowany, jeśli członek jest zainicjalizowany wewnątrz ciała konstruktora, ale nie w liście inicjalizacji?
Odpowiedź:
Nie. Jeśli nie jest to określone w liście inicjalizacji, zmienna najpierw zostanie zainicjalizowana wartością domyślną (domyślny inicjalizator dla członka), a potem w ciele konstruktora nastąpi przypisanie, co jest mniej efektywne.
Jaki jest porządek inicjalizacji członków klasy z domyślnymi inicjalizatorami dla członków przy dziedziczeniu?
Odpowiedź:
Najpierw inicjalizowane są człony klasy bazowej, a następnie pochodnej; dla każdego członka z domyślnym inicjalizatorem dla członka najpierw używana jest lista inicjalizacji konstruktora, jeśli jest podana, a następnie — domyślny inicjalizator dla członka, w przeciwnym razie pozostaje nie zainicjalizowany (dla POD). Nie występuje "podwójna inicjalizacja".
Czy domyślny inicjalizator dla członka może być stosowany do statycznych członków klasy?
Odpowiedź:
Nie, statyczne człony nie mogą być inicjalizowane przez domyślny inicjalizator dla członka. Muszą być inicjowane poza klasą lub za pomocą inline static w C++17.
Przykład:
struct S { static int a = 5; // Błąd! };
Klasa z dynamicznym ciągiem, który został pominięty podczas inicjalizacji w niektórych konstruktorach. Później podczas odwołania — undefined behavior.
Zalety:
Wady:
Wszystkie pola mają domyślne inicjalizatory dla członków. Dodatkowe konstruktory w razie potrzeby jawnie inicjalizują potrzebne człony przez listę inicjalizacji.
Zalety:
Wady: