Aracılığıyla paylaş


Başlatıcılar

Bir başlatıcı bir değişkenin başlangıç değerini belirtir. Değişkenleri şu bağlamlarda başlatabilirsiniz:

  • Bir değişkenin tanımı içinde:

    int i = 3;
    Point p1{ 1, 2 };
    
  • Bir işlevin parametrelerinden biri olarak:

    set_point(Point{ 5, 6 });
    
  • Bir işlevin dönüş değeri olarak:

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

Başlatıcılar şu biçimleri alabilir:

  • Parantez içinde bir ifade (veya virgülle ayrılmış ifadeler listesi):

    Point p1(1, 2);
    
  • Ardından bir ifade gelen bir eşittir işareti:

    string s = "hello";
    
  • Bir küme ayracıyla belirtilen başlatıcı listesi. Liste, aşağıdaki örnekte olduğu gibi boş olabilir veya bir liste kümesinden oluşabilir:

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

Başlatma türleri

Program yürütmesinde farklı noktalarda gerçekleşebilecek çeşitli başlatma türleri vardır. Farklı başlatma türleri birbirini dışlamaz; örneğin, liste başlatma değer başlatmayı tetikleyebilir ve diğer durumlarda toplu başlatmayı tetikleyebilir.

Sıfır başlatma

Sıfır başlatma, sıfır değerindeki bir değişken ayarının örtülü olarak şu türe dönüştürülmesidir:

  • Sayısal değişkenler 0 olarak başlatılır (ya da 0.0 ya da 0.0000000000 vb.).

  • Char değişkenleri olarak '\0'başlatılır.

  • İşaretçiler olarak nullptrbaşlatılır.

  • Diziler, POD sınıfları, yapılar ve birleşimler, üyelerinin sıfır değere başlatılmasını sağlar.

Farklı zamanlarda sıfır başlatma gerçekleştirilir:

  • Program başlangıcında, statik süresi olan tüm adlandırılmış değişkenler için. Bu değişkenler daha sonra yeniden başlatılmış olabilir.

  • Değer başlatma sırasında, boş ayraçlar kullanılarak başlatılan skalar türler ve POD sınıf türleri için.

  • Yalnızca üyelerinin başlattığu bir alt kümesi bulunan diziler.

Sıfır başlatma için bazı örnekler şunlardır:

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'
}

Varsayılan başlatma

Sınıflar, yapılar ve birleşimler için varsayılan başlatma, varsayılan oluşturucuyla başlatılır. Varsayılan oluşturucu başlatma ifadesi olmadan veya anahtar sözcüğüyle new çağrılabilir:

MyClass mc1;
MyClass* mc3 = new MyClass;

Sınıf, yapı veya birleşim varsayılan bir oluşturucuya sahip değilse, derleyici bir hata yayar.

Skaler değişkenler, başlatma ifadesi olmadan tanımlandığında varsayılan olarak başlatılır. Belirsiz değerlere sahiptirler.

int i1;
float f;
char c;

Diziler, başlatma ifadesi olmadan tanımlandığında varsayılan olarak başlatılır. Bir dizi varsayılan olarak başlatıldığında, üyeleri varsayılan olarak başlatılır ve aşağıdaki örnekte olduğu gibi belirsiz değerlere sahiptir:

int int_arr[3];

Dizi üyeleri varsayılan bir oluşturucuya sahip değilse, derleyici bir hata yayar.

Sabit değişkenlerin varsayılan olarak başlatılması

Sabit değişkenlerin bir başlatıcı ile birlikte bildirilmesi gerekir. Skaler türlerse derleyici hatasına neden olurlar ve varsayılan oluşturucuya sahip sınıf türleriyse uyarıya neden olurlar:

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
}

Statik değişkenlerin varsayılan başlatması

Başlatıcı olmadan bildirilen statik değişkenler 0'a başlatılır (örtük olarak türüne dönüştürülür).

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'}
}

Genel statik nesnelerin başlatılması hakkında daha fazla bilgi için bkz . ana işlev ve komut satırı bağımsız değişkenleri.

Değer başlatma

Değer başlatma aşağıdaki durumlarda gerçekleşir:

  • Adlandırılmış bir değer boş küme ayracı başlatması kullanılarak başlatılır

  • Anonim geçici nesne boş ayraçlar veya ayraçlar kullanılarak başlatılır

  • bir nesne anahtar sözcüğü ve new boş ayraçlar veya ayraçlarla başlatılır

Değer başlatma aşağıdakileri yapar:

  • En az bir ortak oluşturucuya sahip sınıflar için varsayılan oluşturucu çağrılır

  • bildirilmemiş oluşturucuları olmayan nonunion sınıfları için nesne sıfır başlatılır ve varsayılan oluşturucu çağrılır

  • diziler için her öğe değer olarak başlatılır

  • diğer tüm durumlarda değişken sıfır başlatılır

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
}

Kopyalama başlatma

Kopyalama başlatma, bir nesnenin farklı bir nesne kullanılarak başlatılmasıdır. Aşağıdaki durumlarda oluşur:

  • bir değişken eşittir işareti kullanılarak başlatılır

  • bir işleve bağımsız değişken geçirilir

  • bir işlevden bir nesne döndürülür

  • özel durum oluştu veya yakalandı

  • Statik olmayan bir veri üyesi eşittir işareti kullanılarak başlatılır

  • sınıf, yapı ve birleşim üyeleri, toplama başlatma sırasında kopya başlatma ile başlatılır. Örnekler için bkz . Toplu başlatma .

Aşağıdaki kod, kopyalama başlatmanın çeşitli örneklerini gösterir:

#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();
    }
}

Kopyalama başlatma açık oluşturucuları çağıramaz.

vector<int> v = 10; // the constructor is explicit; compiler error C2440: can't 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

Bazı durumlarda, sınıfın kopya oluşturucusu silinmişse veya erişilemezse, kopya başlatma bir derleyici hatasına neden olur.

Doğrudan başlatma

Doğrudan başlatma, (boş olmayan) ayraçlar veya parantezler kullanılarak başlatılıyor. Kopya başlatmanın aksine açık oluşturucuları çağırabilir: Aşağıdaki durumlarda oluşur:

  • bir değişken boş olmayan ayraçlar veya ayraçlarla başlatılır

  • bir değişken anahtar sözcüğü ve new boş olmayan ayraçlar veya ayraçlarla başlatılır

  • ile bir değişken başlatılır static_cast

  • oluşturucuda temel sınıflar ve statik olmayan üyeler başlatıcı listesiyle başlatılır

  • bir lambda ifadesinin içinde yakalanan değişkenin kopyasında

Aşağıdaki kod, doğrudan başlatmanın bazı örneklerini gösterir:

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();
}

Liste başlatma

Liste başlatma, bir değişken kümeli başlatıcı listesi kullanılarak başlatıldığında gerçekleşir. Kümeli başlatıcı listeleri aşağıdaki durumlarda kullanılabilir:

  • bir değişken başlatıldı

  • anahtar sözcüğüyle new bir sınıf başlatılır

  • bir işlevden bir nesne döndürülür

  • bir işleve geçirilen bağımsız değişken

  • doğrudan başlatmadaki bağımsız değişkenlerden biri

  • statik olmayan bir veri üyesi başlatıcısında

  • oluşturucu başlatıcı listesinde

Aşağıdaki kod, bazı liste başlatma örneklerini gösterir:

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

Toplu başlatma

Toplama başlatma diziler veya sınıf türleri için (çoğunlukla yapılar veya birlikler) şunlara sahip olan bir liste başlatma biçimidir:

  • özel veya korumalı üye yok

  • açıkça varsayılan veya silinmiş oluşturucular dışında kullanıcı tarafından sağlanan oluşturucular yok

  • temel sınıf yok

  • sanal üye işlevi yok

Not

Visual Studio 2015 ve önceki sürümlerinde, statik olmayan üyeler için küme ayracı veya eşit başlatıcılara sahip bir toplamaya izin verilmez. Bu kısıtlama C++14 standardında kaldırıldı ve Visual Studio 2017'de uygulandı.

Toplama başlatıcıları, aşağıdaki örnekte olduğu gibi eşittir işareti olan veya olmayan bir kümeli başlatma listesinden oluşur:

#include <iostream>
using namespace std;

struct MyAggregate{
    int myInt;
    char myChar;
};

struct MyAggregate2{
    int myInt;
    char myChar = 'Z'; // member-initializer OK in C++14
};

int main() {
    MyAggregate agg1{ 1, 'c' };
    MyAggregate2 agg2{2};
    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;
}

Aşağıdaki çıkışı görmeniz gerekir:

agg1: c: 1
agg2: Z: 2
myArr1: 1 2 3 4
myArr3: 8 9 10 0 0

Önemli

Yukarıda gösterildiği gibi myArr3 , toplu başlatma sırasında açıkça başlatılmayan ancak bildirilen dizi üyeleri sıfır başlatılır.

Birleşimleri ve yapıları başlatma

Bir birleşim oluşturucuya sahip değilse, bunu tek bir değerle (veya birleşimin başka bir örneğiyle) başlatabilirsiniz. Değer, ilk statik olmayan alanı başlatmak için kullanılır. Bu, içinde ilk alanı başlatmak için kullanılan ilk değerin, ikinci alanı başlatmak için ikincinin vb. bulunduğu yapı başlatmadan farklıdır. Birleşimlerin ve yapıların başlatılmasını aşağıdaki örnekte karşılaştırın:

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'
}

Toplamalar içeren toplamaları başlatma

Toplama türleri dizi dizileri, yapı dizileri vb. gibi diğer toplama türlerini içerebilir. Bu türler iç içe küme ayraçları kullanılarak başlatılır, örneğin:

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

Başvuru başlatma

Başvuru türü değişkenleri, başvuru türünün türetildiği türdeki bir nesneyle veya başvuru türünün türetildiği türe dönüştürülebilen bir tür nesnesiyle başlatılmalıdır. Örneğin:

// initializing_references.cpp
int iVar;
long lVar;
int main()
{
    long& LongRef1 = lVar;        // No conversion required.
    long& LongRef2 = iVar;        // Error C2440
    const long& LongRef3 = iVar;  // OK
    LongRef1 = 23L;               // Change lVar through a reference.
    LongRef2 = 11L;               // Change iVar through a reference.
    LongRef3 = 11L;               // Error C3892
}

Geçici bir nesneyle başvuru başlatmanın tek yolu, sabit bir geçici nesne başlatmaktır. Bir başvuru türü değişkeni başlatıldıktan sonra her zaman aynı nesneyi gösterir; başka bir nesneye işaret etmek için değiştirilemez.

Söz dizimi aynı olsa da, başvuru türü değişkenlerin başlatılması ve başvuru türü değişkenlere atamanın ad farkı vardır. Yukarıdaki örnekte, değişen ve lVar başlatmalara iVar benzeyen ancak farklı etkileri olan atamalar. Başlatma, başvuru türü değişkeninin işaret ettiği nesneyi belirtir; atama, başvuru aracılığıyla başvuruda bulunılan nesneye atar.

Hem başvuru türündeki bir bağımsız değişkeni işleve geçirme hem de bir işlevden başvuru türü değeri döndürme işlemi başlatma işlemi olduğundan, döndürülen başvurular gibi işleve yönelik resmi bağımsız değişkenler de doğru şekilde başlatılır.

Başvuru türündeki değişkenler yalnızca aşağıdaki başlatıcılar olmadan bildirilebilir:

  • İşlev bildirimleri (prototipler). Örneğin:

    int func( int& );
    
  • İşlev dönüş türü bildirimleri. Örneğin:

    int& func( int& );
    
  • Başvuru türü sınıf üyesinin bildirimi. Örneğin:

    class c {public:   int& i;};
    
  • açıkça olarak externbelirtilen bir değişkenin bildirimi. Örneğin:

    extern int& iVal;
    

Bir başvuru türü değişkeni başlatılırken, derleyici bir nesneye başvuru oluşturmak veya başvurunun işaret ettiği geçici bir nesne oluşturmak arasında seçim yapmak için aşağıdaki şekilde gösterilen karar grafını kullanır:

Başvuru türlerinin başlatılması için karar grafı.

Karar grafı şununla başlar: başlatıcı aynı türde bir lvalue mu yoksa başvuru türünden türetilmiş bir tür mü? Evet ise, başvuru başlatıcıda belirtilen nesneye başvurur. Hayır ise, bir sonraki karar başvuru türü değişkeninin başlatılmakta olan bir const T başvurusu olup olmadığıdır ve başlatıcı örtük olarak T'ye dönüştürülebilir mi? Evet ise, geçici oluşturulur ve başvuru değişkeni bu geçici için bir ad olur. Hayır ise, bu bir hatadır.

Başvuru türlerinin başlatılması için karar grafı

Tür başvuruları volatile (typename&identifier olarak volatile bildirilmiştir) aynı türdeki nesnelerle volatile veya olarak volatilebildirilmemiş nesnelerle başlatılabilir. Ancak, bu tür nesnelerle const başlatılamazlar. Benzer şekilde, tür başvuruları const (typename&identifier olarak const bildirilmiştir) aynı türdeki nesnelerle const (veya bu türe dönüştürmesi olan veya olarak constbildirilmemiş nesnelerle) başlatılabilir. Ancak, bu tür nesnelerle volatile başlatılamazlar.

veya volatile anahtar sözcüğüyle nitelenmemiş başvurular yalnızca ne ne de volatileconst const olarak bildirilen nesnelerle başlatılabilir.

Dış değişkenleri başlatma

Otomatik, statik ve dış değişkenlerin bildirimleri başlatıcılar içerebilir. Ancak, dış değişkenlerin bildirimleri yalnızca değişkenler olarak externbildirilmeyen başlatıcılar içerebilir.