[basic.scope.pdecl] / 1 dari draft standar C ++ 20 memiliki contoh (non-normatif) berikut dalam catatan (kutipan parsial dari sebelum permintaan tarik gabungan 3580 , lihat jawaban untuk pertanyaan ini):
unsigned char x = x;
[...] x diinisialisasi dengan nilainya sendiri (tidak ditentukan).
Apakah ini sebenarnya memiliki perilaku yang didefinisikan dengan baik di C ++ 20?
Umumnya inisialisasi diri dari formulir T x = x;
memiliki perilaku yang tidak ditentukan berdasarkan x
nilai yang tidak ditentukan sebelum inisialisasi selesai. Mengevaluasi nilai tak tentu umumnya menyebabkan perilaku yang tidak ditentukan ( [basic.indent] / 2 ), tetapi ada pengecualian khusus di [basic.indent] /2.3 yang memungkinkan langsung menginisialisasi unsigned char
variabel dari nilai unsigned char
dengan nilai tak tentu (menyebabkan inisialisasi dengan nilai tak tentu) ).
Ini saja karena itu tidak menyebabkan perilaku yang tidak terdefinisi, tetapi akan untuk tipe lain T
yang bukan tipe karakter sempit yang tidak ditandai atau std::byte
, misalnya int x = x;
. Pertimbangan ini diterapkan di C ++ 17 dan sebelumnya, lihat juga pertanyaan terkait di bagian bawah.
Namun, bahkan untuk unsigned char x = x;
, draft [basic.lifetime] / 7 saat ini mengatakan:
Demikian pula, sebelum masa hidup suatu objek telah dimulai [...] menggunakan properti-properti dari glvalue yang tidak bergantung pada nilainya didefinisikan dengan baik. Program memiliki perilaku yang tidak terdefinisi jika:
glvalue digunakan untuk mengakses objek, atau
[...]
Ini sepertinya menyiratkan bahwa x
nilai dalam contoh hanya dapat digunakan selama masa pakainya.
[basic.lifetime] / 1 mengatakan:
[...]
Masa hidup objek tipe T dimulai ketika:
- [...] dan
- inisialisasi (jika ada) selesai (termasuk inisialisasi kosong) ([dcl.init]),
[...]
Dengan demikian x
masa hidup dimulai hanya setelah inisialisasi selesai. Tetapi dalam contoh yang dikutip x
nilai digunakan sebelum x
inisialisasi selesai. Karena itu penggunaannya memiliki perilaku yang tidak jelas.
Apakah analisis saya benar dan jika ya, apakah itu memengaruhi kasus penggunaan-sebelum-inisialisasi yang serupa seperti
int x = (x = 1);
yang, sejauh yang saya tahu, didefinisikan dengan baik dalam C ++ 17 dan sebelumnya juga?
Perhatikan bahwa dalam C ++ 17 (draft terakhir) persyaratan kedua untuk seumur hidup untuk memulai berbeda :
- jika objek memiliki inisialisasi non-hampa, inisialisasi selesai,
Karena x
akan memiliki inisialisasi kosong dengan definisi C ++ 17 (tetapi bukan yang ada dalam konsep saat ini), masa pakainya akan sudah dimulai ketika diakses di penginisialisasi dalam contoh yang diberikan di atas dan dalam kedua contoh tidak ada perilaku yang tidak ditentukan. karena masa pakai x
dalam C ++ 17.
Kata-kata sebelum C ++ 17 sekali lagi berbeda, tetapi dengan hasil yang sama.
Pertanyaannya bukan tentang perilaku yang tidak terdefinisi saat menggunakan nilai yang tidak ditentukan, yang dicakup dalam misalnya pertanyaan berikut:
int x ^= x;
tidak terbentuk dengan baik secara sintaksis. Anda bisa memiliki definisi variabel dengan penginisialisasi (yaituint x = x;
, meskipun itu adalah UB) atau pernyataan ekspresi tugas atau (yaitux ^= x;
, meskipun itu adalah UB jikax
bertipeint
, default-diinisialisasi dan tidak ditugaskan sebelumnya). Anda tidak dapat mencampur keduanya menjadi satu.Jawaban:
Ini dibuka sebagai masalah editorial . Itu diteruskan ke CWG untuk diskusi (internal). Sekitar 24 jam kemudian, orang yang meneruskan masalah tersebut membuat permintaan tarik yang mengubah contoh untuk memperjelas bahwa ini adalah UB:
Sejak itu PR telah ditambahkan dan masalah ditutup. Jadi tampak jelas bahwa interpretasi yang jelas (UB karena mengakses objek yang masa hidupnya belum dimulai) adalah interpretasi yang dimaksud. Tampaknya maksud dari komite adalah untuk membuat konstruksi ini tidak berfungsi, dan teks non-normatif standar telah diperbarui untuk mencerminkan hal ini.
sumber