logo

När använder vi Initializer List i C++?

Initializer List används för att initiera datamedlemmarna i en klass. Listan över medlemmar som ska initieras indikeras med konstruktor som en kommaseparerad lista följt av ett kolon. Följande är ett exempel som använder initialiseringslistan för att initiera x och y i Point-klassen.

Exempel



C++






#include> using> namespace> std;> class> Point {> private>:> >int> x;> >int> y;> public>:> >Point(>int> i = 0,>int> j = 0): x(i), y(j) {}> >/* The above use of Initializer list is optional as the> >constructor can also be written as:> >Point(int i = 0, int j = 0) {> >x = i;> >y = j;> >}> >*/> >int> getX()>const> {>return> x; }> >int> getY()>const> {>return> y; }> };> int> main()> {> >Point t1(10, 15);> >cout <<>'x = '> << t1.getX() <<>', '>;> >cout <<>'y = '> << t1.getY();> >return> 0;> }>



>

>

Produktion

x = 10, y = 15>

Ovanstående kod är bara ett exempel för syntax för Initializer-listan. I ovanstående kod kan x och y också enkelt initialiseras inuti konstruktorn. Men det finns situationer där initiering av datamedlemmar inuti konstruktorn inte fungerar och Initializer List måste användas. Följande är sådana fall:

1. För initiering av icke-statiska konstdatamedlemmar

const datamedlemmar måste initieras med hjälp av Initializer List. I följande exempel är t en const-datamedlem i testklassen och initieras med hjälp av Initializer List. Anledningen till att initiera const-datamedlemmen i initialiseringslistan är att inget minne är tilldelat separat för const-datamedlemmen, det viks i symboltabellen på grund av vilket vi behöver initiera det i initialiseringslistan.

Det är också en parametriserad konstruktör och vi behöver inte ringa uppdragsoperatören vilket innebär att vi undviker en extra operation.

Exempel

C++




// C++ progmram to demonstrate the use of> // initializer list to initialize the const> // data member> #include> using> namespace> std;> class> Test {> >const> int> t;> public>:> >//Initializer list must be used> >Test(>int> t):t(t) {}> >int> getT() {>return> t; }> };> int> main() {> >Test t1(10);> >cout< return 0; }>

>

>

Produktion

10>

2. För initiering av referensmedlemmar

Referensmedlemmar måste initieras med hjälp av initieringslistan. I följande exempel är t en referensmedlem i testklassen och initieras med hjälp av initieringslistan.

Exempel

C++


maven förråd



// Initialization of reference data members> #include> using> namespace> std;> class> Test {> >int> &t;> public>:> >Test(>int> &t):t(t) {}>//Initializer list must be used> >int> getT() {>return> t; }> };> int> main() {> >int> x = 20;> >Test t1(x);> >cout< x = 30; cout< return 0; }>

>

>

Produktion

20 30>

3. För initiering av medlemsobjekt som inte har en standardkonstruktör

I följande exempel är ett objekt a i klass A en datamedlem i klass B och A har ingen standardkonstruktor. Initialiseringslista måste användas för att initiera en.

Exempel

C++




// C++ progmam to initialize a member object without default> // constructor> #include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> };> A::A(>int> arg)> {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i> ><< endl;> }> // Class B contains object of A> class> B {> >A a;> public>:> >B(>int>);> };> B::B(>int> x) : a(x)> {>// Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main()> {> >B obj(10);> >return> 0;> }>

>

>

Produktion

A's Constructor called: Value of i: 10 B's Constructor called>

Om klass A hade både standardkonstruktorer och parametriserade konstruktorer, är Initializer List inte ett måste om vi vill initiera en med standardkonstruktorn, utan det är ett måste för att initiera en med den parameteriserade konstruktorn.

4. För initiering av basklassmedlemmar

Liksom punkt 3 kan den parametriserade konstruktorn för basklassen endast anropas med hjälp av Initializer List.

Exempel

C++




#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int> );> };> A::A(>int> arg) {> >i = arg;> >cout <<>'A's Constructor called: Value of i: '> << i << endl;> }> // Class B is derived from A> class> B: A {> public>:> >B(>int> );> };> B::B(>int> x):A(x) {>//Initializer list must be used> >cout <<>'B's Constructor called'>;> }> int> main() {> >B obj(10);> >return> 0;> }>

>

>

Produktion

A's Constructor called: Value of i: 10 B's Constructor called>

5. När konstruktörens parameternamn är detsamma som datamedlem

Om konstruktörens parameternamn är detsamma som datamedlemsnamnet måste datamedlemmen initieras antingen med denna pekare eller Initialiseringslista. I följande exempel är både medlemsnamnet och parameternamnet för A() i.

Exempel

C++




#include> using> namespace> std;> class> A {> >int> i;> public>:> >A(>int>);> >int> getI()>const> {>return> i; }> };> A::A(>int> i) : i(i)> {> }>// Either Initializer list or this pointer must be used> /* The above constructor can also be written as> A::A(int i) {> >this->i = i;> }> */> int> main()> {> >A a(10);> >cout << a.getI();> >return> 0;> }>

>

>

Produktion

10>

6. Av prestationsskäl

Det är bättre att initiera alla klassvariabler i Initialiseringslistan istället för att tilldela värden inuti kroppen. Tänk på följande exempel:

Exempel

C++




// 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;> >}> };>

>

>

Här följer kompilatorn följande steg för att skapa ett objekt av typen MyClass

1. Typs konstruktor kallas först för a.

2. Standard konstruktionsvariabel

3. Tilldelningsoperatorn av Typ kallas inuti kroppen av MyClass()-konstruktorn för att tilldela

variable = a;>

4. Och så till slut kallas destructor of Type för en eftersom den går utanför räckvidden.

Tänk nu på samma kod med MyClass()-konstruktorn med Initializer List

C++




// 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> >}> };>

>

hur man hittar bildskärmsstorlek

>

Med initieringslistan följs följande steg av kompilatorn:

1. Typs konstruktor kallas först för a.
2. Parameteriserad konstruktor av typklassen anropas för att initiera: variabel(a). Argumenten i initieringslistan används för att kopiera konstruktionsvariabel direkt.
3. Destruktören av Type kallas för a eftersom den går utanför räckvidden.

Som vi kan se från det här exemplet om vi använder tilldelning i konstruktorkroppen finns det tre funktionsanrop: konstruktor + destruktor + ett tilläggstilldelningsoperatörsanrop. Och om vi använder Initializer List finns det bara två funktionsanrop: copy constructor + destructor call. Se det här inlägget för ett löpande exempel på denna punkt.

Denna tilldelningsstraff kommer att vara mycket mer i verkliga tillämpningar där det kommer att finnas många sådana variabler. Tack vare ptr för att lägga till denna punkt.

Parameter vs enhetlig initiering i C++

Det är bättre att använda en initieringslista med enhetlig initiering {} istället för parameterinitiering () för att undvika problemet med minskande omvandlingar och oväntat beteende. Det ger strängare typkontroll under initiering och förhindrar potentiella minskande konverteringar

Kod med parameterinitiering ()

C++




#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(x); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }>

>

>

Produktion

44>

I ovanstående kod är värdet 300 utanför det giltiga intervallet för char, vilket kan leda till odefinierat beteende och potentiellt felaktiga resultat. Kompilatorn kan generera en varning eller ett fel för denna situation, beroende på kompileringsinställningarna.

Kod med enhetlig initiering {}

Genom att använda enhetlig initiering med {} och initiera x med det angivna värdet a, kommer kompilatorn att utföra strängare typkontroll och utfärda en varning eller ett fel under kompileringen, vilket indikerar den avsmalnande omvandlingen från int till char.
Här finns kod med enhetlig initialisering {} , vilket resulterar i en varning och därmed bättre att använda

C++




#include> class> Base {> >char> x;> public>:> >Base(>char> a)> >: x{ a }> >{> >}> >void> print() { std::cout <<>static_cast><>int>>(x); }> };> int> main()> {> >Base b{ 300 };>// Using uniform initialization with {}> >b.print();> >return> 0;> }>

>

>

main.cpp: In function ‘int main()’: main.cpp:17:17: error: narrowing conversion of ‘300’ from ‘int’ to ‘char’ [-Wnarrowing] 17 | Base b{ 300 }; // Using uniform initialization with {} | ^>