Apa arti frasa berikut dalam C ++: nol-, default- dan inisialisasi nilai?

190

Apa arti dari frasa berikut dalam C ++:

  • nol inisialisasi,

  • inisialisasi default, dan

  • inisialisasi nilai

Apa yang harus diketahui pengembang C ++ tentang mereka?

Tagihan
sumber
1
Ini terkait dengan (tetapi tidak identik dengan) stackoverflow.com/questions/620137/…
Steve Jessop
20
Masih ada lagi! Daftar lengkap inisialisasi: Nilai, langsung, salin, daftar (C ++ 11 intro baru), agregat, referensi, nol, konstan dan default; en.cppreference.com/w/cpp/language/initialization mendaftar semuanya dengan contoh :)
legends2k

Jawaban:

65

Satu hal yang perlu disadari adalah bahwa 'inisialisasi nilai' adalah baru dengan standar C ++ 2003 - tidak ada dalam standar asli 1998 (saya pikir itu mungkin satu-satunya perbedaan yang lebih dari sekadar klarifikasi). Lihat jawaban Kirill V. Lyadvinsky untuk definisi langsung dari standar.

Lihat jawaban sebelumnya tentang perilaku operator newuntuk perincian tentang perilaku yang berbeda dari tipe inisialisasi ini dan kapan mereka melakukan tendangan (dan ketika mereka berbeda dari c ++ 98 ke C ++ 03):

Poin utama dari jawabannya adalah:

Kadang-kadang memori yang dikembalikan oleh operator baru akan diinisialisasi, dan kadang-kadang tidak tergantung pada apakah jenis yang Anda barukan adalah POD, atau apakah itu kelas yang berisi anggota POD dan menggunakan konstruktor default yang dihasilkan kompiler yang dihasilkan .

  • Dalam C ++ 1998 ada 2 jenis inisialisasi: nol dan default
  • Dalam C ++ 2003 jenis inisialisasi ke-3, inisialisasi nilai ditambahkan.

Untuk mengatakannya paling tidak, ini agak rumit dan ketika metode yang berbeda muncul dengan halus.

Satu hal yang perlu diperhatikan adalah bahwa MSVC mengikuti aturan C ++ 98, bahkan dalam VS 2008 (VC 9 atau cl.exe versi 15.x).

Cuplikan berikut menunjukkan bahwa MSVC dan Digital Mars mengikuti aturan C ++ 98, sedangkan GCC 3.4.5 dan Comeau mengikuti aturan C ++ 03:

#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;
}
Michael Burr
sumber
1
Bukan berarti itu penting int, tetapi m()pada nilai baris ketiga menginisialisasi m. Penting jika Anda berubah int m;menjadi B m;. :)
Johannes Schaub - litb
Benar - Adan Ctidak digunakan dalam contoh ini (mereka dibawa dari jawaban terkait lainnya). Meskipun C ++ 98 dan C ++ 03 menggunakan terminologi yang berbeda ketika menggambarkan bagaimana Adan Cdikonstruksi, hasilnya adalah sama di kedua standar. Hanya struct Bmenghasilkan perilaku yang berbeda.
Michael Burr
1
Apa yang saya maksudkan adalah bahwa jika Anda mengubah C menjadi struct C { C() : m() {}; ~C(); B m; };, maka Anda akan m.mmenjadi 0. Tetapi jika itu akan secara default diinisialisasi mseperti yang Anda katakan C ++ 03 lakukan, maka m.mtidak akan diinisialisasi seperti di C ++ 98.
Johannes Schaub - litb
1
Komentar menarik tambahan tentang MSVC menangani fitur ini: stackoverflow.com/questions/3931312/…
Brent Bradburn
Inisialisasi mana yang terjadi ketika Anda mendeklarasikan tipe Anda sebagai variabel lokal, yaitu di stack?
André Puel
89

C ++ 03 Standar 8.5 / 5:

Untuk nol-menginisialisasi sebuah objek sarana tipe T:
- jika T adalah tipe skalar (3,9), objek diatur ke nilai 0 (nol) dikonversi ke T;
- jika T adalah tipe kelas non-serikat, setiap anggota data tidak statis dan setiap sub-proyek kelas dasar diinisialisasi nol;
- jika T adalah tipe gabungan, anggota data pertama bernama objek diinisialisasi nol;
- jika T adalah tipe array, setiap elemen diinisialisasi nol;
- jika T adalah tipe referensi, tidak ada inisialisasi yang dilakukan.

Untuk menginisialisasi-default objek tipe T berarti:
- jika T adalah tipe kelas non-POD (klausa 9), konstruktor default untuk T disebut (dan inisialisasi tidak terbentuk jika T tidak memiliki konstruktor default yang dapat diakses);
- jika T adalah tipe array, setiap elemen diinisialisasi-awal;
- jika tidak, objek diinisialisasi nol.

Untuk menginisialisasi nilai objek tipe T berarti:
- jika T adalah tipe kelas (klausa 9) dengan konstruktor yang dideklarasikan pengguna (12.1), maka konstruktor default untuk T disebut (dan inisialisasi tidak terbentuk jika T tidak memiliki konstruktor default yang dapat diakses);
- jika T adalah tipe kelas non-serikat tanpa konstruktor yang dideklarasikan oleh pengguna, maka setiap anggota data non-statis dan komponen kelas-dasar dari T diinisialisasi-nilai;
- jika T adalah tipe array, maka setiap elemen diinisialisasi-nilai;
- jika tidak, objek diinisialisasi nol

Program yang menyerukan inisialisasi default atau inisialisasi nilai entitas tipe referensi tidak terbentuk. Jika T adalah tipe yang memenuhi syarat cv, versi T yang tidak memenuhi syarat cv digunakan untuk definisi inisialisasi nol, inisialisasi default, dan inisialisasi nilai.

Kirill V. Lyadvinsky
sumber
18
Ini mungkin kedaluwarsa untuk C ++ 11. cppreference.com menyatakan bahwa inisialisasi default tidak menginisialisasi ulang anggota (hanya inisialisasi nilai yang dilakukan).
Alexei Sholik
3
@android memunculkan poin penting, yang saya lihat tidak dijawab di tempat lain, jadi saya telah membuat pertanyaan baru. stackoverflow.com/questions/22233148/…
Adrian McCarthy