Sdílet prostřednictvím


Inicializátory

Inicializátor určuje počáteční hodnotu proměnné.Můžete inicializovat proměnné v těchto kontextech:

  • V definici proměnné:

    int i = 3;
    Point p1{ 1, 2 };
    
  • Jako jeden z parametrů funkce:

    set_point(Point{ 5, 6 });
    
  • Jako návratovou hodnotu funkce:

    Point get_new_point(int x, int y) { return { x, y }; }
    Point get_new_point(int x, int y) { return Point{ x, y }; }
    

Inicializátory mohou mít tyto formy:

  • Výraz (nebo seznam výrazů oddělených čárkami) v závorkách:

    Point p1(1, 2);
    
  • Znaménko rovná se za výrazem:

    string s = "hello";
    
  • Seznam inicializátorů v závorkách.Seznam může být prázdný, nebo může sestávat z několika seznamů:

    struct Point{
        int x;
        int y;
    };
    class PointConsumer{
    public:
        void set_point(Point p){};
        void set_points(initializer_list<Point> my_list){};
    };
    int main() {
        PointConsumer pc{};
        pc.set_point({});
        pc.set_point({ 3, 4 });
        pc.set_points({ { 3, 4 }, { 5, 6 } });
    }
    

Druhy inicializace

Existuje několik druhů inicializace, které mohou nastat v různých fázích provádění programu.Různé druhy inicializace se vzájemně nevylučují, například inicializační seznam může spustit inicializační hodnotu a za jiných okolností to může spustit agregační inicializaci.

Inicializace nula

Inicializace nula je nastavení proměnné na hodnotu nula implicitně převedenou na typ:

  • Číselné proměnné jsou inicializovány na hodnotu 0 (nebo 0,0 nebo 0,0000000000 atd.).

  • Proměnné typu Char jsou inicializovány na hodnotu ‘\0’.

  • Ukazatele jsou inicializovány na nullptr.

  • Pole, třídy POD, struktury a sjednocení mají své členy inicializovány na hodnotu nula.

Inicializace nula je provedena v různých časech:

  • Při spuštění programu pro všechny pojmenované proměnné, které mají statické trvání.Tyto proměnné mohou být později znovu inicializovány.

  • Během inicializace hodnoty pro skalární typy a typy tříd POD, které jsou inicializovány pomocí prázdné závorky.

  • Pro pole, která mají inicializovánu pouze podmnožinu svých členů.

Zde jsou některé příklady inicializace nula:

struct my_struct{
    int i;
    char c;
};

int i0;              // zero-initialized to 0
int main() {
    static float f1;  // zero-initialized to 0.000000000
    double d{};     // zero-initialized to 0.00000000000000000
    int* ptr{};     // initialized to nullptr
    char s_array[3]{'a', 'b'};  // the third char is initialized to '\0'
    int int_array[5] = { 8, 9, 10 };  // the fourth and fifth ints are initialized to 0
    my_struct a_struct{};   // i = 0, c = '\0'
}

Výchozí inicializace

Výchozí inicializace pro třídy, struktury a sjednocení je inicializace, která používá výchozí konstruktor.Výchozí konstruktor může být volán bez zahrnutí výrazu inicializace nebo pomocí klíčového slova new:

MyClass mc1;
MyClass* mc3 = new MyClass;

Pokud třída, struktura nebo sjednocení nemá výchozí konstruktor, kompilátor vydává chybu.

Skalární proměnné jsou inicializována ve výchozím nastavení, když jsou definovány bez výraz inicializace.Mají neurčité hodnoty.

int i1;
float f;
char c;

Pole jsou inicializována ve výchozím nastavení, když jsou definována bez výrazu inicializace.Pokud je pole ve výchozím nastavení inicializováno, jeho členové jsou inicializováni ve výchozím nastavení a mají neurčité hodnoty:

int int_arr[3];

Pokud členové pole nemají výchozí konstruktor, kompilátor vydává chybu.

Výchozí inicializace konstantních proměnných

Konstantní proměnné musí být deklarovány společně s inicializátorem.Pokud jsou skalární typy, způsobují chybu kompilátoru, a pokud jsou typy tříd, které mají výchozí konstruktor, způsobují upozornění:

class MyClass{};
int main() {
    //const int i2;   // compiler error C2734: const object must be initialized if not extern
    //const char c2;  // same error
    const MyClass mc1; // compiler error C4269: 'const automatic data initialized with compiler generated default constructor produces unreliable results
}

Výchozí inicializace statických proměnných

Statické proměnné, které jsou prohlášeny bez inicializátoru, jsou inicializovány na hodnotu 0 (implicitně převedeny na typ):

class MyClass {   
private:
    int m_int;
    char m_char;
};

int main() {
    static int int1;       // 0
    static char char1;     // '\0'
    static bool bool1;   // false
    static MyClass mc1;     // {0, '\0'}
}

Další informace o inicializaci globálních statických objektů naleznete v tématu Další důležité informace o spuštění.

Inicializace hodnoty

V těchto případech dojde k inicializaci hodnoty:

  • Pojmenovaná hodnota je inicializována pomocí inicializace prázdné závorky.

  • Anonymní dočasný objekt je inicializován pomocí prázdných kulatých závorek nebo složených závorek.

  • Anonymní dočasný objekt je inicializován pomocí klíčového slova new a prázdných kulatých závorek nebo složených závorek.

Inicializace hodnoty provede následující:

  • Pro třídy, které mají nejméně jeden veřejný konstruktor, se zavolá výchozí konstruktor.

  • Pro třídy mimo sjednocení, které nemají deklarované konstruktory, je objekt inicializován nulou a je zavolán výchozí konstruktor.

  • Hodnota každého prvku pole je inicializována.

  • Ve všech ostatních případech je proměnná inicializována nulou.

class BaseClass {  
private:
    int m_int;
};

int main() {
    BaseClass bc{};     // class is initialized
    BaseClass*  bc2 = new BaseClass();  // class is initialized, m_int value is 0
    int int_arr[3]{};  // value of all members is 0
    int a{};     // value of a is 0
    double b{};  // value of b is 0.00000000000000000
}

Kopírovat inicializaci

Kopírování inicializace je inicializace jednoho objektu pomocí jiného objektu.Dochází k ní v těchto případech:

  • Proměnná je inicializována pomocí znaménka rovná se.

  • Argument je předán do funkce.

  • Objekt je vrácen z funkce.

  • Výjimka je vyvolána nebo zachycena.

  • Nestatický datový člen je inicializován pomocí znaménka rovná se.

  • Členové třídy, struktury a sjednocení jsou inicializovány kopírováním inicializace během inicializace agregace.Příklady jsou uvedeny v tématu Inicializace agregace.

Tento kód ukazuje příklady kopírování inicializace:

#include <iostream>
using namespace std;

class MyClass{
public:
    MyClass(int myInt) {}
    void set_int(int myInt) { m_int = myInt; }
    int get_int() const { return m_int; }
private:
    int m_int = 7; // copy initialization of m_int

};
class MyException : public exception{};
int main() {
    int i = 5;              // copy initialization of i
    MyClass mc1{ i };
    MyClass mc2 = mc1;      // copy initialization of mc2 from mc1
    MyClass mc1.set_int(i);    // copy initialization of parameter from i
    int i2 = mc2.get_int(); // copy initialization of i2 from return value of get_int()

    try{
        throw MyException();    
    }
    catch (MyException ex){ // copy initialization of ex
        cout << ex.what();  
    }
}

Inicializace kopírování nemůže vyvolat explicitní konstruktory:

vector<int> v = 10; // the constructor is explicit; compiler error C2440: cannot convert from 'int' to 'std::vector<int,std::allocator<_Ty>>'
regex r = "a.*b"; // the constructor is explicit; same error
shared_ptr<int> sp = new int(1729); // the constructor is explicit; same error

V některých případech, pokud je kopírovací konstruktu třídy odstraněn nebo nepřístupný, kopírování inicializace způsobí chybu kompilátoru.Další informace naleznete v tématu Explicitní inicializace.

Přímá inicializace

Přímá inicializace používá (neprázdné) kulaté nebo složené závorky.Na rozdíl od kopírování inicializace nemůže vyvolat explicitní konstruktory.Dochází k ní v těchto případech:

  • Proměnná je inicializována pomocí neprázdných kulatých či složených závorek.

  • Proměnná je inicializována pomocí klíčového slova new a neprázdných kulatých závorek nebo složených závorek.

  • Proměnná je inicializována pomocí static_cast.

  • V konstruktoru jsou základní třídy a nestatické členy inicializovány pomocí seznamu inicializátorů.

  • V kopii zachycené proměnné ve výrazu lambda.

Zde jsou některé příklady přímé inicializace:

class BaseClass{
public:
    BaseClass(int n) :m_int(n){} // m_int is direct initialized
private:
    int m_int;
};

class DerivedClass : public BaseClass{
public:
    // BaseClass and m_char are direct initialized
    DerivedClass(int n, char c) : BaseClass(n), m_char(c) {}
private:
    char m_char;
};
int main(){
    BaseClass bc1(5);
    DerivedClass dc1{ 1, 'c' };
    BaseClass* bc2 = new BaseClass(7);
    BaseClass bc3 = static_cast<BaseClass>(dc1);

    int a = 1;
    function<int()> func = [a](){  return a + 1; }; // a is direct initialized
    int n = func();
}

Inicializace seznamu

Inicializační seznam se vyvolá v případě, že proměnná je inicializována pomocí seznamu inicializátorů v závorkách.Seznamy inicializátorů v závorkách lze použít v těchto případech:

  • Proměnná je inicializována.

  • Třída je inicializována pomocí klíčového slova new.

  • Objekt je vrácen z funkce.

  • Argument je předán funkci.

  • Jeden z argumentů v přímé inicializaci.

  • V inicializátoru nestatických datových členů.

  • V seznamu inicializátorů konstruktoru.

Příklady inicializace seznamu:

class MyClass {
public:
    MyClass(int myInt, char myChar) {}  
private:
    int m_int[]{ 3 };
    char m_char;
};
class MyClassConsumer{
public:
    void set_class(MyClass c) {}
    MyClass get_class() { return MyClass{ 0, '\0' }; }
};
struct MyStruct{
    int my_int;
    char my_char;
    MyClass my_class;
};
int main() {
    MyClass mc1{ 1, 'a' };
    MyClass* mc2 = new MyClass{ 2, 'b' };
    MyClass mc3 = { 3, 'c' };

    MyClassConsumer mcc;
    mcc.set_class(MyClass{ 3, 'c' });
    mcc.set_class({ 4, 'd' });

    MyStruct ms1{ 1, 'a', { 2, 'b' } };
}

Inicializace agregace

Inicializace agregace je forma inicializace seznamu pro pole nebo typy tříd (často struktury nebo sjednocení), které mají:

  • Žádné soukromé nebo chráněné členy.

  • Žádné uživatelem zadané konstruktory s výjimkou výslovně nastavených výchozích nebo odstraněných konstruktorů.

  • Žádné základní třídy.

  • Žádné virtuální členské funkce.

  • Pro nestatické členy žádné inicializátory v závorkách nebo se znaménkem rovná se.

Inicializátory agregace se skládají ze seznamu inicializace v závorkách se znakem rovná se, nebo bez něj:

#include <iostream>
using namespace std;

struct MyAggregate{
    int myInt;
    char myChar;
};

int main() {
    MyAggregate agg1{ 1, 'c' };

    cout << "agg1: " << agg1.myChar << ": " << agg1.myInt << endl;
    cout << "agg2: " << agg2.myChar << ": " << agg2.myInt << endl;

    int myArr1[]{ 1, 2, 3, 4 };
    int myArr2[3] = { 5, 6, 7 };
    int myArr3[5] = { 8, 9, 10 };

    cout << "myArr1: ";
    for (int i : myArr1){
        cout << i << " ";
    }
    cout << endl;
    
    cout << "myArr3: ";
    for (auto const &i : myArr3) {
        cout << i << " ";
    }
    cout << endl;
}

Zde je výstup:

agg1: c: 1
agg2: d: 2
myArr1: 1 2 3 4
myArr3: 8 9 10 0 0
Důležitá poznámkaDůležité

Členy pole, které byly deklarovány, ale během inicializace agregace nebyly explicitně inicializovány, budou inicializovány nulou, viz myArr3.

Inicializace sjednocení a struktur

Pokud sjednocení nemá konstruktor, můžete inicializovat pomocí hodnoty (nebo pomocí jiné instance sjednocení).Hodnota slouží k inicializaci prvního nestatické pole.Tím se liší od inicializace struktury, ve které první hodnota v inicializátoru slouží k inicializaci prvního pole, druhá k inicializaci druhé pole a tak dále.Porovnejte inicializace sjednocení a struktur v tomto příkladu:

struct MyStruct {
    int myInt;
    char myChar;
};
union MyUnion {
    int my_int;
    char my_char;
    bool my_bool;
    MyStruct my_struct;
};

int main() {  
    MyUnion mu1{ 'a' };  // my_int = 97, my_char = 'a', my_bool = true, {myInt = 97, myChar = '\0'}
    MyUnion mu2{ 1 };   // my_int = 1, my_char = 'x1', my_bool = true, {myInt = 1, myChar = '\0'}
    MyUnion mu3{};      // my_int = 0, my_char = '\0', my_bool = false, {myInt = 0, myChar = '\0'}
    MyUnion mu4 = mu3;  // my_int = 0, my_char = '\0', my_bool = false, {myInt = 0, myChar = '\0'}
    //MyUnion mu5{ 1, 'a', true };  // compiler error: C2078: too many initializers
    //MyUnion mu6 = 'a';            // compiler error: C2440: cannot convert from 'char' to 'MyUnion'
    //MyUnion mu7 = 1;              // compiler error: C2440: cannot convert from 'int' to 'MyUnion'

    MyStruct ms1{ 'a' };            // myInt = 97, myChar = '\0'
    MyStruct ms2{ 1 };              // myInt = 1, myChar = '\0'
    MyStruct ms3{};                 // myInt = 0, myChar = '\0'
    MyStruct ms4{1, 'a'};           // myInt = 1, myChar = 'a'
    MyStruct ms5 = { 2, 'b' };      // myInt = 2, myChar = 'b'
}

Inicializace agregátů, které obsahují agregáty

Typy agregátů mohou obsahovat další typy agregátů, například pole polí, pole struktur a tak dále.Tyto typy jsou inicializovány pomocí vnořených sad závorek:

struct MyStruct {
    int myInt;
    char myChar;
};
int main() {
    int intArr1[2][2]{{ 1, 2 }, { 3, 4 }};
    int intArr3[2][2] = {1, 2, 3, 4};  
    MyStruct structArr[]{ { 1, 'a' }, { 2, 'b' }, {3, 'c'} };
}

Inicializace odkazu

Další informace o inicializaci odkazu naleznete v tématu Inicializace odkazů.

Inicializace externích proměnných

Prohlášení o automatických, zaregistrovaných, statických a externích proměnných mohou obsahovat inicializátory.Deklarace externích proměnných však mohou obsahovat inicializátory pouze v případě, že proměnné nejsou deklarovány jako extern.Další informace naleznete v tématu Externí.

Viz také

Referenční dokumentace

Deklarátory