Aşağıdaki ifadeler C ++ 'da ne anlama gelir: sıfır, varsayılan ve değer başlatma?


190

Aşağıdaki ifadeler C ++ ile ne anlama geliyor:

  • sıfır başlatma,

  • varsayılan başlatma ve

  • değer başlatma

Bir C ++ geliştiricisi onlar hakkında ne bilmeli?



20
Fazlası var! Başlatmaların tam listesi: Değer, doğrudan, kopya, liste (C ++ 11 yeni giriş), toplam, referans, sıfır, sabit ve varsayılan; en.cppreference.com/w/cpp/language/initialization hepsini örneklerle listeler :)
legends2k

Yanıtlar:


65

Gerçekleşmesi gereken bir şey, 'değer başlatma' C ++ 2003 standardında yeni olmasıdır - orijinal 1998 standardında mevcut değildir (bir açıklamadan daha fazla olan tek fark olabilir). Doğrudan standarttan tanımlar için Kirill V. Lyadvinsky'nin cevabına bakınız .

Bu operator newbaşlatma türünün farklı davranışları ve ne zaman devreye girdikleri (ve c ++ 98'den C ++ 03'e farklılık gösterdiklerinde) hakkındaki ayrıntılar için önceki davranışına bakın:

Cevabın ana noktası:

Bazen yeni işleç tarafından döndürülen bellek başlatılır ve bazen yeni sürdüğünüz türün POD olmasına veya POD üyeleri içeren ve derleyici tarafından oluşturulan varsayılan kurucu kullanıp kullanmadığına bağlı olmaz. .

  • C ++ 1998'de 2 başlatma türü vardır: sıfır ve varsayılan
  • C ++ 2003'te 3. tür bir başlatma, değer başlatma eklendi.

En azını söylemek gerekirse, oldukça karmaşıktır ve farklı yöntemler devreye girdiğinde süptildir.

Kesinlikle bilinmesi gereken bir şey, MSVC'nin VS 2008'de (VC 9 veya cl.exe sürüm 15.x) bile C ++ 98 kurallarına uymasıdır.

Aşağıdaki snippet, MSVC ve Digital Mars'ın C ++ 98 kurallarına, GCC 3.4.5 ve Comeau'nun C ++ 03 kurallarına uyduğunu göstermektedir:

#include <cstdio>
#include <cstring>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    std::printf( "m  is %d\n", pB->m);
    return 0;
}

1
Önemli olduğu için intdeğil m(), üçüncü satırdaki değer m'yi başlatır. Olarak değiştirirseniz int m;önemlidir B m;. :)
Johannes Schaub - litb

Doğru - Ave Cbu örnekte kullanılmıyor (diğer bağlantılı cevaptan taşınıyor). C ++ 98 ve C ++ 03 nasıl Ave nasıl Cyapılandırıldıklarını açıklarken farklı terminoloji kullansalar da sonuç her iki standartta da aynıdır. Yalnızca struct Bfarklı davranışlarla sonuçlanır.
Michael Burr

1
Demek istediğim, eğer C'yi değiştirirseniz struct C { C() : m() {}; ~C(); B m; };, o zaman m.m0 olacaktır. Ancak mC ++ 03'ün söylediği gibi varsayılan başlangıç yaparsa, m.mC ++ 98'deki gibi başlatılmaz.
Johannes Schaub - litb

1
Bu özelliğin MSVC kullanımı hakkında ek ilginç yorumlar: stackoverflow.com/questions/3931312/…
Brent Bradburn

Türünüzü yerel değişken olarak, yani yığında bildirdiğinizde hangi başlatma gerçekleşir?
André Puel

89

C ++ 03 Standart 8.5 / 5:

İçin sıfır-başlatmak tipi T aracının bir nesne:
- T, bir skaler tipi (3.9) ise, nesne (sıfır), 0 değerine ayarlanır T dönüştürülür;
- T bir birleştirici olmayan sınıf tipiyse, her statik olmayan veri elemanı ve her bir temel sınıf alt nesnesi sıfır başlatılır;
- T birleşim tipiyse, nesnenin ilk adlandırılmış veri üyesi sıfırdan başlatılır;
- T bir dizi tipiyse, her eleman sıfır başlangıç ​​değerine ayarlanır;
- T referans tipiyse, başlatma yapılmaz.

İçin varsayılan-başlatmak tipi T aracının bir nesne:
- T, bir POD olmayan sınıf tipi (bölüm 9) ise, T varsayılan yapıcı olarak adlandırılır (T hiçbir erişilebilir varsayılan kurucu varsa başlatma kötü oluşturulur);
- T bir dizi türüyse, her öğe varsayılan olarak başlatılır;
- aksi takdirde, nesne sıfırla başlatılır.

İçin değer başlangıç durumuna tipi T aracının bir nesne:
- T, bir kullanıcı tarafından beyan kurucu (12.1) ile birlikte bir sınıf türü (bölüm 9) ise, o zaman T varsayılan yapıcı olarak adlandırılır (ve başlatma T ise kötü oluşturulur erişilebilir bir varsayılan kurucuya sahip değildir);
- T, kullanıcı tarafından bildirilmiş bir kurucu içermeyen bir birleşim olmayan sınıf tipiyse, T'nin statik olmayan her veri üyesi ve taban sınıfı bileşeni değerle başlatılır;
- T bir dizi türüyse, her öğe değerle başlatılır;
- aksi takdirde, nesne sıfırdan başlatılır

Referans türündeki bir varlığın varsayılan olarak başlatılmasını veya değer başlatılmasını isteyen bir program yanlış biçimlendirilmiştir. T cv onaylı bir türse, sıfır başlatma, varsayılan başlatma ve değer başlatma gibi tanımlamalar için T'nin cv niteliksiz sürümü kullanılır.


18
Bu, C ++ 11 için eski olabilir. cppreference.com varsayılan başlatma belirtiyor değildir sıfır initialize üyeleri (tek değer başlatma yapar).
Alexei Sholik

3
@android, başka bir yerde yanıtlandığını görmediğim önemli bir noktaya işaret ediyor, bu yüzden yeni bir soru yaptım. stackoverflow.com/questions/22233148/…
Adrian McCarthy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.