Urutan panggilan konstruktor dan destruktor anggota


121

Oh C ++ guru, saya mencari kebijaksanaan Anda. Bicaralah dengan bahasa standar kepada saya dan beri tahu saya jika C ++ menjamin bahwa program berikut:

#include <iostream>
using namespace std;

struct A
{
    A() { cout << "A::A" << endl; }
    ~A() { cout << "A::~" << endl; }
};

struct B
{
    B() { cout << "B::B" << endl; }
    ~B() { cout << "B::~" << endl; }
};

struct C
{
    C() { cout << "C::C" << endl; }
    ~C() { cout << "C::~" << endl; }
};

struct Aggregate
{
    A a;
    B b;
    C c;
};

int main()
{
    Aggregate a;
    return 0;
}

akan selalu menghasilkan

A::A
B::B
C::C
C::~
B::~
A::~

Dengan kata lain, apakah anggota dijamin akan diinisialisasi dengan perintah deklarasi dan dimusnahkan dalam urutan terbalik?


8
Ini adalah penyebab bug halus yang cukup umum ketika kelas telah berkembang menjadi besar dan tidak lemah. Jika Anda memiliki 50 anggota data, dan banyak dari mereka diinisialisasi dalam daftar penginisialisasi konstruktor, akan mudah untuk mengasumsikan urutan konstruksi adalah urutan dalam daftar penginisialisasi. Lagipula, penulis kode telah menyusun daftarnya dengan hati-hati ... bukan?
Permaquid

Jawaban:


140

Dengan kata lain, apakah anggota dijamin akan diinisialisasi dengan perintah deklarasi dan dimusnahkan dalam urutan terbalik?

Ya untuk keduanya. Lihat 12.6.2

6 Inisialisasi akan dilanjutkan dengan urutan sebagai berikut:

  • Pertama, dan hanya untuk konstruktor dari kelas yang paling banyak diturunkan seperti dijelaskan di bawah ini, kelas dasar virtual harus diinisialisasi dalam urutan kemunculannya pada lintasan kiri-ke-kanan pertama kedalaman dari grafik asiklik kelas dasar, di mana "kiri -to-right ”adalah urutan kemunculan nama-nama kelas dasar dalam daftar penentu-dasar kelas turunan.

  • Kemudian, kelas-kelas dasar langsung harus diinisialisasi dalam urutan deklarasi seperti yang muncul dalam daftar-penentu-dasar (terlepas dari urutan penginisialisasi-mem).

  • Kemudian, anggota data non-statis harus diinisialisasi dalam urutan mereka dideklarasikan dalam definisi kelas (sekali lagi terlepas dari urutan penginisialisasi mem).

  • Akhirnya, pernyataan majemuk dari badan konstruktor dijalankan. [Catatan: urutan deklarasi diamanatkan untuk memastikan bahwa sub-objek basis dan anggota dihancurkan dalam urutan terbalik dari inisialisasi. —Kirim catatan]


2
Jika saya ingat dengan benar, ya untuk keduanya ... Anggap saja sebagai tumpukan. Pertama didorong, terakhir muncul. Jadi, saat membuat instance pertama Anda, itu didorong ke dalam memori dalam urutan tumpukan. Kemudian, yang kedua didorong, yang ketiga di atas yang kedua dan seterusnya. Kemudian, saat menghancurkan instance Anda, program akan mencari yang pertama dimusnahkan, yang terakhir didorong. Tapi saya mungkin salah menjelaskannya seperti ini, tetapi itulah cara saya mempelajarinya saat melakukan C / C ++ dan ASM.
Akankah Marcouiller

29

Ya, mereka (yaitu anggota non-statis). Lihat 12.6.2 / 5 untuk inisialisasi (konstruksi) dan 12.4 / 6 untuk penghancuran.


10

Ya, standar menjamin objek dihancurkan dalam urutan terbalik saat dibuat. Alasannya adalah bahwa satu objek dapat menggunakan objek lain, sehingga bergantung padanya. Mempertimbangkan:

struct A { };

struct B {
 A &a;
 B(A& a) : a(a) { }
};

int main() {
    A a;
    B b(a);
}

Jika adihancurkan sebelum bitu bakan memegang referensi anggota yang tidak valid. Dengan menghancurkan objek dalam urutan terbalik saat dibuat, kami menjamin kehancuran yang benar.


Aku tidak pernah benar-benar menganggap bahwa aturan ini berlaku untuk urutan penghancuran anggota scope juga!
yano

6

Ya dan ya. Urutan kehancuran selalu berlawanan dengan urutan konstruksi, untuk variabel anggota.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.