(Latar belakang: Saya memiliki pengalaman menerapkan kompiler C dan C ++.)
Panjang array variabel di C99 pada dasarnya salah langkah. Untuk mendukung VLA, C99 harus membuat konsesi berikut ini untuk akal sehat:
sizeof x
tidak lagi selalu konstan waktu kompilasi; kompiler terkadang harus menghasilkan kode untuk mengevaluasi sizeof
ekspresi-saat runtime.
Membiarkan Vlas dua dimensi ( int A[x][y]
) diperlukan sintaks baru untuk menyatakan fungsi yang mengambil 2D Vlas sebagai parameter: void foo(int n, int A[][*])
.
Tidak terlalu penting di dunia C ++, tetapi sangat penting bagi audiens target C dari pemrogram sistem tertanam, mendeklarasikan VLA berarti mengompres tumpukan stack Anda secara sewenang - wenang . Ini adalah stack-overflow dan crash yang dijamin . (Kapan saja Anda menyatakan int A[n]
, Anda secara implisit menyatakan bahwa Anda memiliki 2GB stack untuk cadangan. Setelah semua, jika Anda tahu " n
pasti kurang dari 1000 di sini", maka Anda hanya akan menyatakan int A[1000]
. Mengganti integer 32-bit n
untuk 1000
adalah pengakuan Anda tidak tahu seperti apa perilaku program Anda seharusnya.)
Oke, jadi mari kita beralih ke berbicara tentang C ++ sekarang. Dalam C ++, kami memiliki perbedaan kuat yang sama antara "sistem tipe" dan "sistem nilai" yang dilakukan C89 ... tapi kami benar-benar mulai mengandalkannya dengan cara yang tidak dimiliki C. Sebagai contoh:
template<typename T> struct S { ... };
int A[n];
S<decltype(A)> s; // equivalently, S<int[n]> s;
Jika n
bukan konstanta waktu kompilasi (yaitu, jika A
jenisnya diubah secara variatif), lalu apa jenisnya S
? Apakah S
tipe juga hanya akan ditentukan saat runtime?
Bagaimana dengan ini:
template<typename T> bool myfunc(T& t1, T& t2) { ... };
int A1[n1], A2[n2];
myfunc(A1, A2);
Kompiler harus menghasilkan kode untuk beberapa contoh myfunc
. Seperti apa kode itu? Bagaimana kita dapat secara statis menghasilkan kode itu, jika kita tidak tahu tipe A1
pada waktu kompilasi?
Lebih buruk lagi, bagaimana jika ternyata pada saat runtime itu n1 != n2
, jadi begitu !std::is_same<decltype(A1), decltype(A2)>()
? Dalam hal ini, panggilan kemyfunc
bahkan tidak boleh dikompilasi , karena pengurangan tipe template harus gagal! Bagaimana mungkin kita meniru perilaku itu saat runtime?
Pada dasarnya, C ++ bergerak ke arah mendorong semakin banyak keputusan ke dalam waktu kompilasi : pembuatan kode templat, constexpr
evaluasi fungsi, dan sebagainya. Sementara itu, C99 sibuk mendorong keputusan waktu kompilasi tradisional (misalnya sizeof
) ke dalam runtime . Dengan pemikiran ini, apakah itu benar-benar bahkan masuk akal untuk mengeluarkan upaya berusaha untuk mengintegrasikan Vlas C99 bergaya dalam C ++?
Seperti yang sudah ditunjukkan oleh setiap penjawab lain, C ++ menyediakan banyak mekanisme alokasi-tumpukan ( std::unique_ptr<int[]> A = new int[n];
atau std::vector<int> A(n);
menjadi yang jelas) ketika Anda benar-benar ingin menyampaikan gagasan "Saya tidak tahu berapa banyak RAM yang mungkin saya butuhkan." Dan C ++ menyediakan model penanganan pengecualian yang bagus untuk menghadapi situasi yang tak terhindarkan bahwa jumlah RAM yang Anda butuhkan lebih besar dari jumlah RAM yang Anda miliki. Tapi semoga jawaban ini memberi Anda ide bagus mengapa VLA gaya C99 tidak cocok untuk C ++ - dan bahkan tidak cocok untuk C99. ;)
Untuk lebih lanjut tentang topik ini, lihat N3810 "Alternatif untuk Ekstensi Array" , makalah Bjarne Stroustrup Oktober 2013 tentang VLA. Pjar Bjarne sangat berbeda dengan milikku; N3810 lebih fokus pada menemukan ish C ++ yang bagus sintaksis untuk hal-hal, dan pada mengecilkan penggunaan array mentah di C ++, sedangkan saya lebih fokus pada implikasi untuk metaprogramming dan sistem types. Saya tidak tahu apakah dia menganggap implikasi metaprogramming / sistem huruf diselesaikan, dipecahkan, atau hanya tidak menarik.
Sebuah posting blog yang bagus yang mengenai banyak poin yang sama ini adalah "Penggunaan Array Panjang Variabel yang Sah" (Chris Wellons, 2019-10-27).