Saya memiliki struct dengan banyak anggota dengan tipe yang sama, seperti ini
struct VariablePointers {
VariablePtr active;
VariablePtr wasactive;
VariablePtr filename;
};
Masalahnya adalah jika saya lupa menginisialisasi salah satu anggota struct (mis wasactive
), seperti ini:
VariablePointers{activePtr, filename}
Kompiler tidak akan mengeluh tentang hal itu, tetapi saya akan memiliki satu objek yang sebagian diinisialisasi. Bagaimana saya bisa mencegah kesalahan semacam ini? Saya bisa menambahkan konstruktor, tetapi itu akan menduplikasi daftar variabel dua kali, jadi saya harus mengetik semua ini tiga kali!
Harap juga tambahkan jawaban C ++ 11 , jika ada solusi untuk C ++ 11 (saat ini saya terbatas pada versi itu). Namun, standar bahasa yang lebih baru juga diterima!
c++
aggregate-initialization
Johannes Schaub - litb
sumber
sumber
-Wmissing-field-initializers
bendera kompilasi.Jawaban:
Berikut adalah trik yang memicu kesalahan tautan jika inisialisasi yang diperlukan tidak ada:
Pemakaian:
Hasil:
Peringatan:
Foo
agregat sama sekali.sumber
Foo
dinyatakan, bahkan jika Anda tidak pernah benar-benar memanggil operator.Untuk dentang dan gcc Anda dapat mengkompilasi dengan
-Werror=missing-field-initializers
yang mengubah peringatan pada inisialisasi bidang yang hilang menjadi kesalahan.godboltSunting: Untuk MSVC, sepertinya tidak ada peringatan yang dipancarkan bahkan di level
/Wall
, jadi saya rasa tidak mungkin untuk memperingatkan tentang inisialisasi yang hilang dengan kompiler ini. godboltsumber
Bukan solusi yang elegan dan praktis, saya kira ... tetapi harus bekerja juga dengan C ++ 11 dan memberikan kesalahan waktu kompilasi (bukan waktu tautan).
Idenya adalah menambahkan di struct Anda anggota tambahan, di posisi terakhir, dari tipe tanpa inisialisasi default (dan yang tidak dapat menginisialisasi dengan nilai tipe
VariablePtr
(atau apa pun jenis nilai sebelumnya)Contohnya
Dengan cara ini Anda dipaksa untuk menambahkan semua elemen dalam daftar inisialisasi agregat Anda, termasuk nilai untuk secara eksplisit menginisialisasi nilai terakhir (bilangan bulat untuk
sentinel
, dalam contoh) atau Anda mendapatkan "panggilan ke konstruktor yang dihapus dari kesalahan 'bar'".Begitu
kompilasi dan
tidak.
Sayangnya juga
tidak dikompilasi.
- EDIT -
Seperti yang ditunjukkan oleh MSalters (terima kasih) ada cacat (cacat lain) dalam contoh asli saya:
bar
nilai dapat diinisialisasi denganchar
nilai (yang dapat dikonversi keint
), jadi bekerja inisialisasi berikutdan ini bisa sangat membingungkan.
Untuk menghindari masalah ini, saya telah menambahkan konstruktor template yang dihapus berikut
jadi
f4
deklarasi sebelumnya memberikan kesalahan kompilasi karenad
nilainya dicegat oleh konstruktor template yang dihapussumber
foo f;
gagal membuat kompilasi, tapi mungkin itu lebih merupakan fitur daripada cacat dengan trik ini. Akan menerima jika tidak ada proposal yang lebih baik dari ini.enum
, dan namainit_list_end
(o hanyalist_end
) nilai ituenum
; tetapi keterbacaan menambah banyak ketikan, jadi, mengingat bahwa nilai tambahan adalah titik lemah dari jawaban ini, saya tidak tahu apakah itu ide yang bagus.constexpr static int eol = 0;
di headerbar
.test{a, b, c, eol}
sepertinya cukup mudah dibaca oleh saya.bar::eol
; hampir melewatienum
nilai; tetapi saya tidak berpikir itu penting: inti dari jawabannya adalah "tambahkan di struct Anda anggota tambahan, di posisi terakhir, dari jenis tanpa inisialisasi default"; yangbar
bagian hanyalah sebuah contoh sepele untuk menunjukkan bahwa solusi bekerja; "tipe tanpa inisialisasi default" yang tepat harus bergantung pada keadaan (IMHO).Untuk CppCoreCheck ada aturan untuk memeriksa persis itu, jika semua anggota telah diinisialisasi dan yang dapat diubah dari peringatan menjadi kesalahan - yang biasanya tentu saja di seluruh program.
Memperbarui:
Aturan yang ingin Anda periksa adalah bagian dari typesafety
Type.6
:sumber
Cara paling sederhana adalah tidak memberikan tipe anggota konstruktor tanpa argumen:
Opsi lain: Jika anggota Anda adalah const &, Anda harus menginisialisasi semuanya:
Jika Anda dapat hidup dengan satu const & member dummy, Anda dapat menggabungkannya dengan ide @ max66 tentang seorang penjaga.
Dari cppreference https://en.cppreference.com/w/cpp/language/aggregate_initialization
Pilihan lain adalah mengambil ide sentinel max66 dan menambahkan gula sintaksis agar mudah dibaca
sumber
A
digerakkan dan mengubah semantik-copy (A
bukan agregat nilai lagi, jadi untuk berbicara) :(1,2,3
benda-benda tersebut secara efektif adalah penduduk lokal dalam penyimpanan otomatis yang keluar dari ruang lingkup ketika fungsi berakhir. Dan itu membuat sizeof (A) 24 bukannya 3 pada sistem dengan pointer 64-bit (seperti x86-64).