Varsayılan, değer ve sıfır başlatma karmaşası


89

Değer & varsayılan & sıfır başlatma konusunda kafam çok karışık. ve özellikle farklı standartlar C ++ 03 ve C ++ 11 (ve C ++ 14 ) için devreye girdiklerinde .

Burada gerçekten iyi bir cevabı alıntılamakta ve genişletmeye çalışıyorum Value- / Default- / Zero- Init C ++ 98 ve C ++ 03'ü daha genel hale getirmek için, çünkü birileri doldurmaya yardımcı olabilirse birçok kullanıcıya yardımcı olur. Ne zaman ne olacağı hakkında iyi bir genel bakışa sahip olmak için boşluklara ihtiyaç vardı?

Özetle örneklerle tam kavrayış:

Bazen yeni operatör tarafından döndürülen bellek başlatılır ve bazen yeni yazacağınız türün bir POD (düz eski veriler) olup olmadığına veya POD üyeleri içeren ve bir derleyici tarafından üretilen varsayılan yapıcı.

  • In 1998 C ++ : başlatma 2 tipi vardır sıfır ve varsayılan başlatma
  • Gelen 2003 C ++ başlatma, bir 3 tipi katma değer başlatma ilave edildi.
  • In C ++ 2011 / C ++ 2014 tek liste başlatma eklendi ve kuralları değer-/ default- / sıfır başlatma biraz değişti.

Varsayalım:

struct A { int m; };                     
struct B { ~B(); int m; };               
struct C { C() : m(){}; ~C(); int m; };  
struct D { D(){}; int m; };             
struct E { E() = default; int m;}; /** only possible in c++11/14 */  
struct F {F(); int m;};  F::F() = default; /** only possible in c++11/14 */

Bir C ++ 98 derleyicisinde aşağıdakiler gerçekleşmelidir :

  • new A - belirsiz değer ( APOD'dur)
  • new A()- sıfır başlatma
  • new B - varsayılan yapı ( B::mbaşlatılmamış, BPOD değil)
  • new B()- varsayılan yapı ( B::mbaşlatılmamış)
  • new C - varsayılan yapı ( C::msıfır başlatılmıştır, CPOD değildir)
  • new C()- varsayılan yapı ( C::msıfır başlatılmış)
  • new D - varsayılan yapı ( D::mbaşlatılmamış, DPOD değil)
  • new D()- varsayılan yapı? ( D::mbaşlatılmamış)

Bir C ++ 03 uyumlu derleyicide, işler şu şekilde çalışmalıdır:

  • new A - belirsiz değer ( APOD'dur)
  • new A() - value-initialize A, bu bir POD olduğundan sıfır başlatmadır.
  • new B - varsayılan olarak başlatılır ( B::mbaşlatılmamış bırakır , BPOD değildir)
  • new B() - Bvarsayılan ctor kullanıcı tanımlı yerine derleyici oluşturulduğundan, tüm alanları sıfır olarak başlatan değer.
  • new C - default-başlatılır C, varsayılan ctor'u çağırır. ( C::msıfır başlatılmış, CPOD değil)
  • new C() - değer başlatılır C, varsayılan ctor'u çağırır. ( C::msıfır başlatılmış)
  • new D - varsayılan yapı ( D::mbaşlatılmamış, DPOD değil)
  • new D() - değer D'yi başlatır? , varsayılan ctor'u çağıran ( D::mbaşlatılmamış)

İtalik değerler ve? belirsizlik var, lütfen bunu düzeltmeye yardım edin :-)

Bir C ++ 11 uyumlu derleyicide, işler şu şekilde çalışmalıdır:

??? (lütfen yardım edin, buradan başlarsam yine de ters gidecek)

Bir C ++ 14 uyumlu derleyicide, işler şu şekilde çalışmalıdır: ??? (lütfen buradan başlarsam yardım edin, yine de yanlış gidecek) (Yanıta göre taslak)

  • new A - varsayılan başlatır A, derleyici gen. ctor, ( A::mbaşlatılmamış olarak kalır ) (POD'dur A)

  • new A() - değer başlatılır A, bu, [dcl.init] / 8'deki 2. noktadan beri sıfır başlatmadır

  • new B - varsayılan başlatır B, derleyici gen. ctor, ( B::mbaşlatılmamış olarak kalır ) ( BPOD değildir)

  • new B() - Bvarsayılan ctor kullanıcı tanımlı yerine derleyici oluşturulduğundan, tüm alanları sıfır olarak başlatan değer.

  • new C - default-başlatılır C, varsayılan ctor'u çağırır. ( C::msıfır başlatılmış, CPOD değil)

  • new C() - değer başlatılır C, varsayılan ctor'u çağırır. ( C::msıfır başlatılmış)

  • new D - varsayılan olarak başlatılır D( D::mbaşlatılmamış, DPOD değil)

  • new D() - değer başlatılır D, varsayılan ctor'u çağırır ( D::mbaşlatılmamıştır)

  • new E - varsayılan olarak başlatılır E, bu da comp'i çağırır. gen. ctor. ( E::mbaşlatılmamış, E, POD değil)

  • new E() - [dcl.init] / 8'de 2 noktadan beri Esıfır olarak başlayan değer başlatılır )E

  • new F - varsayılan olarak başlatılır F, bu da comp'i çağırır. gen. ctor. ( F::mbaşlatılmamış, FPOD değil)

  • new F() - değer başlatılırken F, varsayılan-başlatılırken F 1. nokta beri [dcl.init] / 8 ( Fo kullanıcısının bildirdiği ve açıkça varsayılan veya ilk bildiriminde silinmiş ise ctor fonksiyonu kullanıcı tarafından sağlanan olduğunu. Bağlantı )



1
Anladığım kadarıyla, bu örneklerde sadece C ++ 98 ve C ++ 03 arasında bir fark var. Sorun N1161 (bu belgenin daha sonraki revizyonları var) ve CWG DR # 178'de açıklanmış gibi görünüyor . Üslup nedeniyle yeni özellikler ve POD yeni şartnameye C ++ 11 değişim için gerekli ve bunun nedeni C ++ 11 kelimelerde kusurlarından C ++ 14'de yine değişti, ama bu gibi durumlarda etkisi değişmez .
dyp

3
Sıkıcı olsa da struct D { D() {}; int m; };listenize dahil etmeye değer olabilir.
Yakk - Adam Nevraumont

Yanıtlar:


24

C ++ 14 new, [expr.new] / 17 ([expr.new] / 15 in C ++ 11'de oluşturulmuş nesnelerin başlatılmasını belirtir ve o zamanlar not bir not değil, normatif metin):

Bir tür nesnesi oluşturan yeni bir ifade , To nesneyi şu şekilde başlatır:

  • Eğer yeni başlatıcı atlanırsa, amacı, varsayılan başlatıldı (8.5). [ Not: Başlatma yapılmazsa, nesnenin belirsiz bir değeri vardır. - son not ]
  • Aksi takdirde, yeni başlatıcı , doğrudan başlatma için 8.5 ilklendirme kurallarına göre yorumlanır .

Varsayılan başlatma [dcl.init] / 7'de tanımlanmıştır (C ++ 11'de / 6 ve ifadenin kendisi aynı etkiye sahiptir):

Bir tür nesneyi varsayılan olarak başlatmak için şu Tanlama gelir:

  • Eğer Tbir (muhtemelen ev nitelikli) sınıf tipi (Madde 9), varsayılan yapıcı (12.1) olduğu T(adlandırılır ve eğer başlatma kötü oluşturulur Tvarsayılan kurucu ya da aşırı yük çözünürlük (belirsiz bir veya 13.3) sonuçları vardır sıfırlama bağlamından silinen veya erişilemeyen bir işlev);
  • Eğer Tbir dizi türü, her bir öğe olduğu varsayılan-başlatıldı ;
  • aksi takdirde başlatma gerçekleştirilmez.

Böylece

  • new Ayalnızca Avarsayılan kurucunun çağrılmasına neden olur , bu da başlatılmaz m. Belirsiz değer. İçin aynı olmalıdır new B.
  • new A() [dcl.init] / 11'e göre yorumlanır (C ++ 11'de / 10):

    İlklendiricisi boş bir parantez kümesi olan bir nesne, yani, ()değer-ilklendirilmiş olacaktır.

    Ve şimdi [dcl.init] / 8 (/ 7 içinde C ++ 11 †) olarak düşünün:

    İçin değer başlangıç durumuna tipi bir nesne Taracı:

    • Eğer Tkullanıcı tarafından sağlanan veya silinmiş olan bir varsayılan kurucu (12.1) veya bir varsayılan kurucu ya sahip bir (muhtemelen ev nitelikli) sınıf tipi (Madde 9), nesnenin varsayılan başlatıldı olduğu;
    • Eğer Tbir kullanıcı tarafından sağlanan veya silinmiş varsayılan kurucu olmayan bir (muhtemelen ev nitelikli) sınıf tipi, daha sonra nesnenin sıfır başlatıldı ve varsayılan başlatma semantik kısıtları kontrol edilir ve T, bir önemsiz olmayan varsayılan kurucu varsa, nesne varsayılan olarak başlatılmıştır;
    • Eğer Tbir dizi türü, daha sonra her bir eleman değer başlatıldı olduğu;
    • aksi takdirde, nesne sıfır başlatılır.

    Bu nedenle new A()sıfır başlatılacaktır m. Ve bu Ave için eşdeğer olmalıdır B.

  • new Cve new C()son alıntıdan itibaren ilk madde işareti uygulandığından nesneyi varsayılan olarak yeniden başlatacaktır (C, kullanıcı tarafından sağlanan bir varsayılan kurucuya sahiptir!). Ancak, açıkça, şimdi mher iki durumda da kurucuda başlatılmıştır.


† Pekala, bu paragraf C ++ 11'de biraz farklı bir ifadeye sahip, bu da sonucu değiştirmiyor:

İçin değer başlangıç durumuna tipi bir nesne Taracı:

  • Eğer Tbir kullanıcı tarafından sağlanan kurucu (12.1) ile birlikte bir (muhtemelen ev nitelikli) sınıf tipi (Madde 9), daha sonra da varsayılan yapıcı T olarak adlandırılır (T hiçbir erişilebilir varsayılan kurucu varsa başlatma kötü oluşturulur);
  • Eğer Tbir kullanıcı tarafından sağlanan yapıcı olmayan bir (muhtemelen ev nitelikli) birleşik-olmayan sınıf tipi ise, o zaman bir amacı, sıfır başlatıldı ve Tdolaylı ilan varsayılan yapıcı olmayan önemsiz s' bu yapıcı olarak adlandırılır.
  • Eğer Tbir dizi türü, daha sonra her bir eleman değer başlatıldı olduğu;
  • aksi takdirde, nesne sıfır başlatılır.

ah, yani esas olarak c ++ 14'ten bahsediyorsunuz ve c ++ 11 için referanslar parantez içinde verilmiştir
Gabriel

@Gabriel Doğru. Demek istediğim, C ++ 14 en son standart, bu yüzden ön plana çıkıyor.
Columbo

1
Başlatma kurallarını standartlar arasında izlemeye çalışmanın can sıkıcı yanı, yayınlanan C ++ 14 ve C ++ 11 standartları arasındaki değişikliklerin çoğunun (çoğu? Tümü?) DR'ler aracılığıyla gerçekleşmesi ve fiilen C ++ 11'in olmasıdır. . Ve ayrıca C ++ 14 sonrası DR'ler de var ...
TC

@Columbo Hala neden struct A { int m; }; struct C { C() : m(){}; int m; };farklı sonuçlar ürettiğini ve A'daki m'nin ilk başta başlatılmasına neyin sebep olduğunu hala anlamıyorum . Yaptığım deney için özel bir ileti dizisi açtım ve sorunu açıklığa kavuşturmak için oradaki girdinizi takdir edeceğim. Teşekkürler stackoverflow.com/questions/45290121/…
darkThoughts

12

Aşağıdaki cevap, C ++ 98 ve C ++ 03 için bir referans görevi görecek olan cevabı https://stackoverflow.com/a/620402/977038 genişletir.

Cevaptan alıntı yapmak

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

C ++ 11 (n3242'ye göre)

Başlatıcılar

8.5 Başlatıcılar [dcl.init], bir değişken POD'un veya POD olmayanın, küme ayracı veya eşitleme başlatıcısı olarak başlatılabileceğini belirtir; bu, ya parantez-init-list veya başlatıcı-cümlesi toplu olarak küme ayracı veya eşit- olarak anılır. başlatıcı veya (ifade-listesi) kullanma . C ++ 11'den önce, yalnızca (ifade listesi) veya başlatıcı yan tümcesi destekleniyordu, ancak başlatıcı yan tümcesi , C ++ 11'de sahip olduklarımızdan daha kısıtlıydı. C ++ 11'de, başlatıcı yan tümcesi artık atama ifadesinden ayrı olarak ayraçlı init listesini destekliyorC ++ 03'te olduğu gibi. Aşağıdaki dilbilgisi, C ++ 11 standardına yeni eklenen bölümün kalın olduğu yeni desteklenen cümleyi özetler.

başlatıcı:
    küme ayracı veya eşitleme başlatıcı
    (ifade-listesi)
küme ayracı veya eşitleme başlatıcı:
    = başlatıcı yan tümcesi
    ayraçlı init-list
başlatıcı yan tümcesi:
    atama-ifade
    çaprazlı-init-list
başlatıcı-listesi:
    başlatıcı yan tümcesi ... opt
    initializer-list, initializer-clause ... opt **
braced-init-list:
    {initializer-list, opt}
    {}

Başlatma

C ++ 03 gibi, C ++ 11 hala üç başlatma biçimini destekliyor


Not

Kalın vurgulanan kısım C ++ 11'e eklenmiş ve üstü çizili kısım C ++ 11'den kaldırılmıştır.

  1. Başlatıcı Türü: 8.5.5 [dcl.init] _zero-initialize_

Aşağıdaki durumlarda gerçekleştirildi

  • Statik veya iş parçacığı depolama süresi olan nesneler sıfır başlatılır
  • Dizi elemanlarından daha az sayıda başlatıcı varsa, açıkça başlatılmamış her eleman sıfır başlatılmış olacaktır.
  • Değer başlatma sırasında , T, kullanıcı tarafından sağlanan bir oluşturucu olmayan (muhtemelen cv nitelikli) birleşmeyen bir sınıf türü ise, nesne sıfır başlatılır.

T türü bir nesneyi veya başvuruyu sıfır başlatmak için şu anlama gelir:

  • T, bir skaler tür (3.9) ise, nesne, bir integral sabit ifade olarak alınan , T'ye dönüştürülen 0 (sıfır) değerine ayarlanır ;
  • T (muhtemelen cv nitelikli) birleşmeyen bir sınıf türü ise, her statik olmayan veri üyesi ve her temel sınıf alt nesnesi sıfır olarak başlatılır ve doldurma sıfır bit olarak başlatılır;
  • T bir (muhtemelen cv nitelikli) birleşim tipiyse , nesnenin statik olmayan ilk adlandırılmış veri üyesi sıfır başlatılır ve doldurma sıfır bit olarak başlatılır;
  • T bir dizi tipiyse, her eleman sıfır ile başlatılır;
  • T bir referans tip ise, başlatma gerçekleştirilmez.

2. Başlatıcı Türü: 8.5.6 [dcl.init] _default-initialize_

Aşağıdaki durumlarda gerçekleştirildi

  • Yeni başlatıcı atlanırsa, nesne varsayılan olarak başlatılır; başlatma gerçekleştirilmezse, nesnenin belirsiz değeri vardır.
  • Bir nesne için başlatıcı belirtilmezse, statik veya iş parçacığı depolama süresi olan nesneler dışında nesne varsayılan olarak başlatılır.
  • Bir yapıcı başlatıcı listesinde bir temel sınıf veya statik olmayan bir veri üyesinden bahsedilmediğinde ve bu yapıcı çağrıldığında.

T türünde bir nesneyi varsayılan olarak başlatmak için şu anlama gelir:

  • T (muhtemelen cv nitelikli) olmayan POD sınıf tipiyse (Madde 9), T için varsayılan kurucu çağrılır (ve T'nin erişilebilir varsayılan kurucusu yoksa başlatma hatalı biçimlidir);
  • T bir dizi tipiyse, her öğe varsayılan olarak başlatılır;
  • aksi takdirde başlatma gerçekleştirilmez.

Not C ++ 11'e kadar, yalnızca otomatik depolama süresi olan POD dışı sınıf türlerinin, başlatıcı kullanılmadığında varsayılan olarak başlatıldığı kabul edilirdi.


3. Başlatıcı Türü: 8.5.7 [dcl.init] _value-initialize_

  1. Başlatıcı boş bir parantez kümesi olan bir nesne (adsız geçici, adlandırılmış değişken, dinamik depolama süresi veya statik olmayan veri üyesi), yani () veya ayraçlar {}

T türünde bir nesneyi değerle başlatmak için şu anlama gelir:

  • T, kullanıcı tarafından sağlanan bir kurucuya (12.1) sahip (muhtemelen cv nitelikli) bir sınıf türü (Madde 9) ise, T için varsayılan kurucu çağrılır (ve T'nin erişilebilir varsayılan kurucusu yoksa başlatma kötü biçimlidir) ;
  • T, kullanıcı tarafından sağlanan bir kurucu olmadan (muhtemelen cv nitelikli) birleşmeyen bir sınıf türü ise, T'nin her statik olmayan veri üyesi ve temel sınıf bileşeni değer olarak başlatılır; bu durumda nesne sıfır başlatılır ve eğer T'nin örtük olarak bildirilen varsayılan kurucusu önemsiz değilse, bu kurucu çağrılır.
  • T bir dizi tipiyse, o zaman her eleman değerle başlatılır;
  • aksi takdirde, nesne sıfır başlatılır.

Yani özetlemek için

Not Standarttan ilgili alıntı kalın olarak vurgulanmıştır.

  • yeni A: varsayılan olarak başlatılır (A :: m'yi başlatılmamış bırakır)
  • yeni A (): Başlatılan değer adayının kullanıcı tarafından sağlanan veya silinen varsayılan kurucusu olmadığından, A'yı sıfırlayın. T, kullanıcı tarafından sağlanan bir oluşturucu olmayan (muhtemelen cv nitelikli) birleşmeyen bir sınıf türüyse, nesne sıfır olarak başlatılır ve T'nin örtük olarak bildirilen varsayılan kurucusu önemsiz değilse, bu kurucu çağrılır.
  • yeni B: varsayılan-başlatılır (B :: m'yi başlatılmamış bırakır)
  • yeni B (): tüm alanları sıfır olarak başlatan B'yi değer olarak başlatır; T, kullanıcı tarafından sağlanan bir kurucuya (12.1) sahip (muhtemelen cv nitelikli) bir sınıf türü (Madde 9) ise, T için varsayılan kurucu çağrılır
  • yeni C: varsayılan - varsayılan ctor'u çağıran C'yi başlatır. T (muhtemelen cv nitelikli) bir sınıf türü ise (Madde 9), T için varsayılan kurucu çağrılır , Üstelik Yeni başlatıcı atlanırsa, nesne varsayılan olarak başlatılır
  • yeni C (): değeri C'yi başlatır ve varsayılan ctor'u çağırır. T, kullanıcı tarafından sağlanan bir kurucuya (12.1) sahip (muhtemelen cv nitelikli) bir sınıf türü (Madde 9) ise, T için varsayılan kurucu çağrılır. Ayrıca, başlatıcısı boş bir parantez kümesi olan bir nesne, yani (), değer olarak başlatılacaktır.

0

C ++ 11'de C ++ 14 altındaki soruda bahsedilen her şeyin en azından derleyici uygulamalarına göre doğru olduğunu onaylayabilirim.

Bunu doğrulamak için aşağıdaki kodu test paketime ekledim . -std=c++11 -O3GCC 7.4.0, GCC 5.4.0, Clang 10.0.1 ve VS 2017 ile test ettim ve aşağıdaki tüm testler geçti.

#include <gtest/gtest.h>
#include <memory>

struct A { int m;                    };
struct B { int m;            ~B(){}; };
struct C { int m; C():m(){}; ~C(){}; };
struct D { int m; D(){};             };
struct E { int m; E() = default;     };
struct F { int m; F();               }; F::F() = default;

// We use this macro to fill stack memory with something else than 0.
// Subsequent calls to EXPECT_NE(a.m, 0) are undefined behavior in theory, but
// pass in practice, and help illustrate that `a.m` is indeed not initialized
// to zero. Note that we initially tried the more aggressive test
// EXPECT_EQ(a.m, 42), but it didn't pass on all compilers (a.m wasn't equal to
// 42, but was still equal to some garbage value, not zero).
//
#define FILL { int m = 42; EXPECT_EQ(m, 42); }

// We use this macro to fill heap memory with something else than 0, before
// doing a placement new at that same exact location. Subsequent calls to
// EXPECT_EQ(a->m, 42) are undefined behavior in theory, but pass in practice,
// and help illustrate that `a->m` is indeed not initialized to zero.
//
#define FILLH(b) std::unique_ptr<int> bp(new int(42)); int* b = bp.get(); EXPECT_EQ(*b, 42)

TEST(TestZero, StackDefaultInitialization)
{
    { FILL; A a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; B a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; C a; EXPECT_EQ(a.m, 0); }
    { FILL; D a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a; EXPECT_NE(a.m, 0); } // UB!
    { FILL; F a; EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, StackValueInitialization)
{
    { FILL; A a = A(); EXPECT_EQ(a.m, 0); }
    { FILL; B a = B(); EXPECT_EQ(a.m, 0); }
    { FILL; C a = C(); EXPECT_EQ(a.m, 0); }
    { FILL; D a = D(); EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a = E(); EXPECT_EQ(a.m, 0); }
    { FILL; F a = F(); EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, StackListInitialization)
{
    { FILL; A a{}; EXPECT_EQ(a.m, 0); }
    { FILL; B a{}; EXPECT_EQ(a.m, 0); }
    { FILL; C a{}; EXPECT_EQ(a.m, 0); }
    { FILL; D a{}; EXPECT_NE(a.m, 0); } // UB!
    { FILL; E a{}; EXPECT_EQ(a.m, 0); }
    { FILL; F a{}; EXPECT_NE(a.m, 0); } // UB!
}

TEST(TestZero, HeapDefaultInitialization)
{
    { FILLH(b); A* a = new (b) A; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); B* a = new (b) B; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); C* a = new (b) C; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); F* a = new (b) F; EXPECT_EQ(a->m, 42); } // ~UB
}

TEST(TestZero, HeapValueInitialization)
{
    { FILLH(b); A* a = new (b) A(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); B* a = new (b) B(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); C* a = new (b) C(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D(); EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E(); EXPECT_EQ(a->m, 0);  }
    { FILLH(b); F* a = new (b) F(); EXPECT_EQ(a->m, 42); } // ~UB
}

TEST(TestZero, HeapListInitialization)
{
    { FILLH(b); A* a = new (b) A{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); B* a = new (b) B{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); C* a = new (b) C{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); D* a = new (b) D{}; EXPECT_EQ(a->m, 42); } // ~UB
    { FILLH(b); E* a = new (b) E{}; EXPECT_EQ(a->m, 0);  }
    { FILLH(b); F* a = new (b) F{}; EXPECT_EQ(a->m, 42); } // ~UB
}

int main(int argc, char **argv)
{
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Yerleri UB!belirtilen tanımsız davranış, ve gerçek davranış (birçok faktöre bağlıdır muhtemeldir a.m42, 0, ya da başka bir çöp eşit olabilir). ~UBBahsedilen yerler teorik olarak tanımlanmamış davranışlardır, ancak pratikte, yeni bir yerleştirmenin kullanılması nedeniyle, a->m42'den başka herhangi bir şeye eşit olma olasılığı çok düşüktür .

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.