MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Mengapa?
Saya tidak dapat menemukan jawaban di SO, jadi izinkan saya menjawab pertanyaan saya sendiri.
MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Mengapa?
Saya tidak dapat menemukan jawaban di SO, jadi izinkan saya menjawab pertanyaan saya sendiri.
auto
?std::map<std::string, std::vector<std::string>>::const_iterator
ingin bicara dengan Anda.using MyContainer = std::map<std::string, std::vector<std::string>>;
lebih baik (terutama karena Anda dapat templat itu!)Jawaban:
Pada dasarnya menyalin dan menempel dari Bjarne Stroustrup "The C ++ Programming Language 4th Edition" :
Inisialisasi daftar tidak memungkinkan penyempitan (§.88.4.4). Itu adalah:
Contoh:
Satu- satunya situasi di mana = lebih disukai daripada {} adalah ketika menggunakan
auto
kata kunci untuk mendapatkan jenis yang ditentukan oleh penginisialisasi.Contoh:
Kesimpulan
Lebih suka {} inisialisasi daripada alternatif kecuali Anda memiliki alasan kuat untuk tidak melakukannya.
sumber
()
bisa diuraikan sebagai deklarasi fungsi. Ini membingungkan dan tidak konsisten yang bisa Anda katakanT t(x,y,z);
tetapi tidakT t()
. Dan kadang-kadang, Anda yakinx
, Anda bahkan tidak bisa mengatakannyaT t(x);
.std::initializer_list
. RedXIII menyebutkan masalah ini (dan hanya mengabaikannya), sedangkan Anda benar-benar mengabaikannya.A(5,4)
danA{5,4}
dapat memanggil fungsi yang sama sekali berbeda, dan ini adalah hal yang penting untuk diketahui. Bahkan dapat mengakibatkan panggilan yang tampaknya tidak intuitif. Mengatakan bahwa Anda harus memilih{}
secara default akan membuat orang salah paham tentang apa yang terjadi. Tapi ini bukan salahmu. Saya pribadi berpikir ini adalah fitur yang dipikirkan dengan sangat buruk.auto var{ 5 }
dan akan disimpulkanint
tidak lebih daristd::initializer_list<int>
.Sudah ada jawaban yang bagus tentang keuntungan menggunakan inisialisasi daftar, namun aturan pribadi saya adalah TIDAK untuk menggunakan kurung kurawal bila memungkinkan, tetapi sebaliknya membuatnya tergantung pada makna konseptual:
Untuk satu, dengan cara itu saya selalu yakin bahwa objek akan diinisialisasi terlepas dari apakah itu misalnya kelas "nyata" dengan konstruktor default yang akan dipanggil tetap atau tipe builtin / POD. Kedua itu - dalam banyak kasus - konsisten dengan aturan pertama, sebagai objek default diinisialisasi sering mewakili objek "kosong".
Dalam pengalaman saya, aturan ini dapat diterapkan jauh lebih konsisten daripada menggunakan kurung kurawal secara default, tetapi harus secara eksplisit mengingat semua pengecualian ketika mereka tidak dapat digunakan atau memiliki makna yang berbeda dari sintaks pemanggilan fungsi "normal" dengan tanda kurung (memanggil kelebihan beban yang berbeda).
Misalnya cocok dengan tipe perpustakaan standar seperti
std::vector
:sumber
const int &b{}
<- tidak mencoba membuat referensi yang tidak diinisialisasi, tetapi mengikatnya ke objek integer sementara. Contoh kedua:struct A { const int &b; A():b{} {} };
<- tidak mencoba membuat referensi yang tidak diinisialisasi (seperti yang()
akan dilakukan), tetapi mengikatnya ke objek integer sementara, dan kemudian membiarkannya menggantung. GCC bahkan dengan-Wall
tidak memperingatkan untuk contoh kedua.Ada alasan BANYAK untuk inisialisasi penggunaan brace, tetapi Anda harus menyadari bahwa yang
initializer_list<>
konstruktor lebih disukai untuk konstruktor lain , pengecualian menjadi default-konstruktor. Ini mengarah ke masalah dengan konstruktor dan template di manaT
konstruktor tipe dapat berupa daftar penginisialisasi atau ctor tua yang polos.Dengan asumsi Anda tidak menemukan kelas-kelas seperti itu, ada sedikit alasan untuk tidak menggunakan daftar intializer.
sumber
{ ... }
) kecuali Anda menginginkaninitializer_list
semantiknya (well, dan mungkin untuk membangun objek secara default).std::initializer_list
aturan itu ada - itu hanya menambah kebingungan dan kekacauan pada bahasa. Apa yang salah dengan melakukanFoo{{a}}
jika Anda menginginkanstd::initializer_list
konstruktor? Tampaknya itu jauh lebih mudah dipahami daripadastd::initializer_list
lebih diutamakan daripada semua kelebihan lainnya.Foo{{a}}
mengikuti beberapa logika bagi saya jauh lebih dariFoo{a}
yang berubah menjadi prioritas daftar intializer (mungkin ups pengguna berpikir hm ...)std::initializer_list<Foo>
konstruktor, tetapi akan ditambahkan keFoo
kelas di beberapa titik untuk memperluas antarmuka? Kemudian penggunaFoo
kelas kacau.initializer_list<>
), yang tidak memenuhi syarat siapa mengatakan itu lebih disukai, dan kemudian mulai menyebutkan satu kasus bagus di mana itu TIDAK disukai. Apa yang saya lewatkan itu ~ 30 orang lain (per 2016-04-21) menemukan bermanfaat?Ini hanya lebih aman selama Anda tidak membangun dengan -Sekarang menyempit seperti kata Google di Chromium. Jika Anda melakukannya, maka itu KURANG aman. Tanpa tanda itu, hanya case yang tidak aman akan diperbaiki oleh C ++ 20 sekalipun.
Catatan: A) Kurung keriting lebih aman karena tidak memungkinkan penyempitan. B) Kurung kurawal kurang aman karena mereka dapat memotong konstruktor pribadi atau dihapus, dan memanggil konstruktor bertanda eksplisit secara implisit.
Kedua gabungan itu berarti mereka lebih aman jika apa yang ada di dalamnya adalah konstanta primitif, tetapi kurang aman jika mereka adalah objek (meskipun tetap dalam C ++ 20)
sumber