Mempertimbangkan:
struct Person
{
int height;
int weight;
int age;
};
int main()
{
Person p { .age = 18 };
}
Kode di atas legal di C99, tetapi tidak legal di C ++ 11.
Apa itu c ++ 11 alasan komite standar untuk mengecualikan dukungan untuk fitur praktis seperti itu?
OVERLAPPED
adalah contohnya. Mampu menulis={.Offset=12345};
akan membuat kode lebih jelas (dan mungkin tidak terlalu rentan terhadap kesalahan). Soket BSD adalah contoh serupa.main
C99 tidak legal. Seharusnya terbacastruct Person p = { .age = 18 };
Jawaban:
C ++ memiliki konstruktor. Jika masuk akal untuk menginisialisasi hanya satu anggota maka itu dapat diekspresikan dalam program dengan menerapkan konstruktor yang sesuai. Ini adalah jenis abstraksi yang dipromosikan C ++.
Di sisi lain, fitur penginisialisasi yang ditunjuk lebih tentang mengekspos dan membuat anggota mudah diakses secara langsung dalam kode klien. Ini mengarah pada hal-hal seperti memiliki seseorang yang berusia 18 (tahun?) Tetapi dengan tinggi dan berat badan nol.
Dengan kata lain, penginisialisasi yang ditunjuk mendukung gaya pemrograman di mana internal diekspos, dan klien diberikan fleksibilitas untuk memutuskan bagaimana mereka ingin menggunakan tipe tersebut.
C ++ lebih tertarik untuk menempatkan fleksibilitas di sisi desainer dari suatu tipe, sehingga desainer dapat membuatnya mudah untuk menggunakan tipe dengan benar dan sulit untuk digunakan secara tidak benar. Menempatkan desainer untuk mengontrol bagaimana sebuah tipe dapat diinisialisasi adalah bagian dari ini: desainer menentukan konstruktor, inisialisasi dalam kelas, dll.
sumber
Person
pembuatnya ingin memberikan fleksibilitas yang paling mungkin bagi pengguna untuk mengatur dan menginisialisasi anggota? Pengguna juga sudah bisa menulisPerson p = { 0, 0, 18 };
(dan untuk alasan yang bagus).Person
memiliki desain yang sangat C sehingga fitur C mungkin masuk akal. Namun C ++ mungkin memungkinkan desain yang lebih baik yang juga meniadakan kebutuhan penginisialisasi yang ditentukan. - Dalam pandangan saya, menghapus pembatasan inisialisasi di kelas untuk agregat jauh lebih sejalan dengan etos C ++ daripada penginisialisasi yang ditunjuk.Pada tanggal 15 Juli '17 P0329R4 diterima dic ++ 20standar: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
Ini membawa dukungan terbatas untukc99Inisialisasi yang Ditunjuk. Batasan ini dijelaskan sebagai berikut oleh C.1.7 [diff.decl] .4, diberikan:
Inisialisasi yang Ditunjuk berikut ini, yang valid di C, dibatasi di C ++:
struct A a = { .y = 1, .x = 2 }
tidak valid di C ++ karena penunjuk harus muncul dalam urutan deklarasi anggota dataint arr[3] = { [1] = 5 }
tidak valid di C ++ karena inisialisasi yang ditunjuk larik tidak didukungstruct B b = {.a.x = 0}
tidak valid di C ++ karena penunjuk tidak dapat bertingkatstruct A c = {.x = 1, 2}
tidak valid di C ++ karena semua atau tidak satu pun anggota data harus diinisialisasi oleh penunjukUntuk c ++ 17dan Boost sebelumnya sebenarnya memiliki dukungan untuk Intializers yang Ditunjuk dan ada banyak proposal untuk menambahkan dukungan kec ++standar, misalnya: n4172 dan Proposal Daryle Walker untuk Menambahkan Penunjukan ke Penginisialisasi . Proposal mengutip implementasic99Penginisialisasi yang Ditunjuk dalam Visual C ++, gcc, dan Clang mengklaim:
Tetapi komite standar berulang kali menolak proposal tersebut , dengan menyatakan:
Komentar Ben Voigt telah membantu saya melihat masalah yang tidak dapat diatasi dengan pendekatan ini; diberikan:
Dalam urutan apa fungsi-fungsi ini dipanggil c99:
struct X foo = {.a = (char)f(), .b = g(), .c = h()}
? Anehnya, dic99:(Visual C ++, gcc , dan Clang tampaknya memiliki perilaku yang disepakati karena mereka semua akan melakukan panggilan dalam urutan ini :)
h()
f()
g()
Tetapi sifat standar yang tidak dapat ditentukan berarti bahwa jika fungsi-fungsi ini memiliki interaksi apa pun, status program yang dihasilkan juga akan tidak dapat ditentukan, dan kompilator tidak akan memperingatkan Anda : Adakah Cara untuk Memperingatkan tentang Penginisialisasi yang Ditunjuk yang Tidak Beraturan?c ++ memang memiliki persyaratan daftar penginisialisasi yang ketat 11.6.4 [dcl.init.list] 4:
Begitu c ++ dukungan akan meminta ini untuk dieksekusi dalam urutan:
f()
g()
h()
Memecah kompatibilitas dengan sebelumnya c99implementasi.
Seperti dibahas di atas, masalah ini telah dielakkan oleh batasan pada Penginisialisasi yang Ditunjuk yang diterimac ++ 20. Mereka menyediakan perilaku standar, menjamin urutan eksekusi Penginisialisasi yang Ditunjuk.
sumber
struct X { int c; char a; float b; }; X x = { .a = f(), .b = g(), .c = h() };
panggilan keh()
dilakukan sebelumf()
ataug()
. Jika definisistruct X
tidak dekat, ini akan sangat mengejutkan. Ingatlah bahwa ekspresi penginisialisasi tidak harus bebas efek samping.Sedikit peretasan, jadi berbagi untuk kesenangan saja.
Dan gunakan seperti:
yang berkembang menjadi:
sumber
$
tipeT
, dan Anda menetapkan anggotanya secara langsung sebelum mengembalikannya. Bagus. Saya ingin tahu apakah ada masalah kinerja dengannya.Penginisialisasi yang ditunjuk saat ini disertakan dalam badan kerja C ++ 20: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf jadi kami mungkin akhirnya melihatnya!
sumber
&
operator akan mengembalikan alamat yang akan dimiliki objek selama masa pakainya).Dua Fitur Core C99 yang C ++ 11 Lacks menyebutkan "Designated Initializers dan C ++".
Saya pikir 'penginisialisasi yang ditunjuk' terkait dengan pengoptimalan potensial. Di sini saya menggunakan “gcc / g ++” 5.1 sebagai contoh.
Kami tahu pada saat kompilasi,
a_point.x
adalah nol, jadi kami bisa berharap bahwafoo
dioptimalkan menjadi satuprintf
.foo
dioptimalkan untuk mencetakx == 0
saja.Untuk versi C ++,
Dan ini adalah keluaran dari kode assemble yang dioptimalkan.
Kita dapat melihat bahwa
a_point
sebenarnya bukan nilai konstanta waktu kompilasi.sumber
constexpr point(int _x,int _y):x(_x),y(_y){}
. clang ++ tampaknya menghilangkan perbandingan dalam kode Anda juga. Jadi, ini hanya masalah QoI.struct addrinfo
ataustruct sockaddr_in
, jadi Anda memiliki tugas yang terpisah dari deklarasi.