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é |
---|
Č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í.