Apakah mungkin untuk menginisialisasi struct di C ++ seperti yang ditunjukkan di bawah ini
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Tautan di sini dan di sini menyebutkan bahwa adalah mungkin untuk menggunakan gaya ini hanya dalam C. Jika demikian mengapa ini tidak mungkin di C ++? Apakah ada alasan teknis yang mendasari mengapa itu tidak diimplementasikan dalam C ++, atau apakah itu praktik yang buruk untuk menggunakan gaya ini. Saya suka menggunakan cara inisialisasi ini karena struct saya besar dan gaya ini memberi saya keterbacaan yang jelas tentang nilai apa yang diberikan kepada anggota mana.
Silakan bagikan dengan saya jika ada cara lain agar kami dapat mencapai keterbacaan yang sama.
Saya telah merujuk tautan berikut sebelum memposting pertanyaan ini
Jawaban:
Jika Anda ingin memperjelas apa nilai masing-masing penginisialisasi, cukup bagi menjadi beberapa baris, dengan komentar pada masing-masing:
sumber
char*
) sebagai salah satu anggota lain di atas atau di bawah dalam struktur, karena tidak ada risiko menukar mereka.(struct timeval){ .seconds = 0, .microseconds = 100 }
akan selalu menjadi seratus mikrodetik, tetapitimeval { 0, 100 }
mungkin seratus DETIK . Anda tidak ingin menemukan hal seperti itu dengan cara yang sulit.Setelah pertanyaan saya menghasilkan hasil yang tidak memuaskan (karena C ++ tidak mengimplementasikan init berbasis tag untuk struktur), saya mengambil trik yang saya temukan di sini: Apakah anggota struct C ++ diinisialisasi ke 0 secara default?
Bagi Anda itu sama saja dengan melakukan itu:
Ini tentunya yang paling dekat dengan apa yang Anda inginkan pada awalnya (nol semua bidang kecuali yang ingin Anda inisialisasi).
sumber
static address temp_address = {};
akan bekerja. Mengisi itu setelahnya sudah sampai ke runtime, ya. Anda dapat melewati ini dengan menyediakan fungsi statis yang melakukan init untuk Anda:static address temp_address = init_my_temp_address();
.init_my_temp_address
bisa menjadi fungsi lambda:static address temp_address = [] () { /* initialization code */ }();
address
dan Anda tidak akan pernah tahu semua tempat yang membuataddress
dan sekarang tidak menginisialisasi anggota baru Anda.Seperti yang disebutkan orang lain, ini disebut sebagai inisialisasi.
Fitur ini adalah bagian dari C ++ 20
sumber
Pengidentifikasi bidang memang sintaks initializer C. Dalam C ++ hanya memberikan nilai dalam urutan yang benar tanpa nama bidang. Sayangnya ini berarti Anda harus memberikan semuanya (sebenarnya Anda dapat menghilangkan trailing kolom bernilai nol dan hasilnya akan sama):
sumber
Fitur ini disebut inisialisasi yang ditunjuk . Ini merupakan tambahan untuk standar C99. Namun, fitur ini tidak disertakan dalam C ++ 11. Menurut Bahasa Pemrograman C ++, edisi ke 4, Bagian 44.3.3.2 (Fitur C Tidak Diadopsi oleh C ++):
Tata bahasa C99 memiliki inisialisasi yang ditunjuk [Lihat ISO / IEC 9899: 2011, Draf Komite N1570 - 12 April 2011]
6.7.9 Inisialisasi
Di sisi lain, C ++ 11 tidak memiliki inisialisasi yang ditunjuk [Lihat ISO / IEC 14882: 2011, N3690 Committee Draft - 15 Mei 2013]
8.5 Inisialisasi
Untuk mencapai efek yang sama, gunakan konstruktor atau daftar penginisialisasi:
sumber
Anda cukup menginisialisasi melalui ctor:
sumber
struct address
. Juga, tipe POD sering sengaja tidak memiliki konstruktor dan destruktor.Anda bahkan dapat mengemas solusi Gui13 ke dalam pernyataan inisialisasi tunggal:
Penafian: Saya tidak merekomendasikan gaya ini
sumber
address
dan kode masih akan dikompilasi dengan satu juta tempat hanya menginisialisasi lima anggota asli. Bagian terbaik dari inisialisasi struct adalah Anda dapat memiliki semua anggotaconst
dan itu akan memaksa Anda untuk menginisialisasi mereka semuaSaya tahu pertanyaan ini cukup lama, tetapi saya menemukan cara lain untuk menginisialisasi, menggunakan constexpr dan currying:
Metode ini juga berfungsi untuk variabel statis global dan bahkan variabel constexpr. Satu-satunya kelemahan adalah pemeliharaan yang buruk: Setiap kali anggota lain harus dibuat diinisialisasi menggunakan metode ini, semua metode inisialisasi anggota harus diubah.
sumber
Saya mungkin kehilangan sesuatu di sini, mengapa tidak:
sumber
Itu tidak diimplementasikan dalam C ++. (juga,
char*
string? Saya harap tidak).Biasanya jika Anda memiliki begitu banyak parameter itu adalah bau kode yang cukup serius. Tetapi sebaliknya, mengapa tidak hanya menginisialisasi nilai struct dan kemudian menetapkan masing-masing anggota?
sumber
char*
string? Kuharap tidak)." - Ya, itu adalah contoh C.char*
tetapiconst char*
jauh lebih aman dari tipe dan semua orang hanya menggunakanstd::string
karena jauh lebih dapat diandalkan.Saya menemukan cara ini untuk variabel global, yang tidak perlu memodifikasi definisi struktur asli:
kemudian deklarasikan variabel tipe baru yang diwarisi dari tipe struct asli dan gunakan konstruktor untuk inisialisasi bidang:
Meskipun tidak cukup elegan dengan gaya C ...
Untuk variabel lokal memerlukan memset tambahan (ini, 0, sizeof (* this)) di awal konstruktor, jadi jelas tidak lebih buruk dan jawaban @ gui13 lebih tepat.
(Perhatikan bahwa 'temp_address' adalah variabel dengan tipe 'temp_address', namun tipe baru ini mewarisi dari 'address' dan dapat digunakan di setiap tempat di mana 'address' diharapkan, jadi tidak masalah.)
sumber
Saya menghadapi masalah yang sama hari ini, di mana saya memiliki struct yang ingin saya isi dengan data uji yang akan diteruskan sebagai argumen ke fungsi yang saya uji. Saya ingin memiliki vektor dari struct ini dan sedang mencari metode satu-liner untuk menginisialisasi setiap struct.
Saya akhirnya pergi dengan fungsi konstruktor di struct, yang saya percaya juga disarankan dalam beberapa jawaban untuk pertanyaan Anda.
Mungkin praktik yang buruk untuk memiliki argumen ke konstruktor memiliki nama yang sama dengan variabel anggota publik, yang memerlukan penggunaan
this
pointer. Seseorang dapat menyarankan suntingan jika ada cara yang lebih baik.Yang saya gunakan di dalam fungsi pengujian saya untuk memanggil fungsi yang sedang diuji dengan berbagai argumen seperti ini:
sumber
Itu mungkin, tetapi hanya jika struct yang Anda inisialisasi adalah struct POD (data lama biasa). Itu tidak dapat berisi metode, konstruktor, atau bahkan nilai default.
sumber
Dalam C ++ inisialisasi style-C digantikan oleh konstruktor yang dengan waktu kompilasi dapat memastikan bahwa hanya inisialisasi yang dilakukan (yaitu setelah inisialisasi anggota objek konsisten).
Ini adalah praktik yang baik, tetapi kadang-kadang pra-inisialisasi berguna, seperti pada contoh Anda. OOP memecahkan ini dengan kelas abstrak atau pola desain kreasi .
Menurut pendapat saya, menggunakan cara aman ini membunuh kesederhanaan dan kadang-kadang pertukaran keamanan mungkin terlalu mahal, karena kode sederhana tidak memerlukan desain canggih untuk tetap dapat dipertahankan.
Sebagai solusi alternatif, saya menyarankan untuk mendefinisikan macro menggunakan lambdas untuk menyederhanakan inisialisasi agar terlihat seperti gaya-C:
Makro ADDRESS diperluas ke
yang membuat dan memanggil lambda. Parameter makro juga dipisahkan oleh koma, jadi Anda harus memasukkan initializer ke dalam tanda kurung dan memanggil seperti
Anda juga bisa menulis penginisialisasi makro umum
tapi kemudian panggilan itu sedikit kurang indah
namun Anda dapat mendefinisikan makro ALAMAT menggunakan makro INIT umum dengan mudah
sumber
Di GNUC ++ (tampaknya sudah usang sejak 2.5, dahulu sekali :) Lihat jawabannya di sini: Inisialisasi C struct menggunakan label. Berhasil, tetapi bagaimana? ), dimungkinkan untuk menginisialisasi struct seperti ini:
sumber
Terinspirasi oleh jawaban yang sangat rapi ini: ( https://stackoverflow.com/a/49572324/4808079 )
Anda dapat melakukan penutupan lamba:
.
Atau, jika Anda ingin menjadi sangat mewah
Ada beberapa kelemahan terkait hal ini, sebagian besar berkaitan dengan anggota yang tidak diinisialisasi. Dari apa yang dikatakan komentar jawaban terkait, ia mengkompilasi secara efisien, meskipun saya belum mengujinya.
Secara keseluruhan, saya hanya berpikir itu pendekatan yang rapi.
sumber