Penggunaan variabel dalam initializer sendiri

22

[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 xnilai 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 charvariabel dari nilai unsigned chardengan nilai tak tentu (menyebabkan inisialisasi dengan nilai tak tentu) ).

Ini saja karena itu tidak menyebabkan perilaku yang tidak terdefinisi, tetapi akan untuk tipe lain Tyang 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 xnilai 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 xmasa hidup dimulai hanya setelah inisialisasi selesai. Tetapi dalam contoh yang dikutip xnilai digunakan sebelum xinisialisasi 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 xakan 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 xdalam 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:

kenari
sumber
@LanguageLawyer Saya tidak yakin bahwa saya benar, terutama tidak jika belum ada yang menjawab. Jika orang lain akan setuju dengan saya di sini, saya mungkin mengajukan satu nanti (atau mungkin orang lain sebelum saya), tetapi saya tidak ingin mengajukan masalah yang saya tidak yakin.
kenari
@LanguageLawyer: Ini tidak bisa menjadi masalah editorial jika kertas kerja dengan jelas mengatakan hal yang salah.
Davis Herring
1
Kata tersebut diubah oleh P1358 .
xskxzr
1
@xskxzr Benar, dan sementara itu LanguageLawyer juga mengajukan masalah editorial , yang tampaknya telah diteruskan ke CWG untuk klarifikasi maksud.
kenari
1
@ clockw0rk int x ^= x;tidak terbentuk dengan baik secara sintaksis. Anda bisa memiliki definisi variabel dengan penginisialisasi (yaitu int x = x;, meskipun itu adalah UB) atau pernyataan ekspresi tugas atau (yaitu x ^= x;, meskipun itu adalah UB jika xbertipe int, default-diinisialisasi dan tidak ditugaskan sebelumnya). Anda tidak dapat mencampur keduanya menjadi satu.
walnut

Jawaban:

8

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:

Di sini, inisialisasi \ tcode {x} kedua memiliki perilaku tidak terdefinisi, karena initializer mengakses \ tcode {x} kedua di luar masa pakai \ iref {basic.life}.

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.

Nicol Bolas
sumber