Jawabannya adalah: itu tergantung pada standar C ++ yang Anda kompilasi. Semua kode dibentuk dengan sempurna di semua standar ‡ dengan pengecualian baris ini:
char * s = "My String";
Sekarang, string literal memiliki tipe const char[10]
dan kami mencoba untuk menginisialisasi pointer non-const untuk itu. Untuk semua jenis selain char
keluarga string literal, inisialisasi seperti itu selalu ilegal. Sebagai contoh:
const int arr[] = {1};
int *p = arr; // nope!
Namun, di pra-C ++ 11, untuk string literal, ada pengecualian di §4.2 / 2:
Sebuah string literal (2.13.4) yang bukan literal string lebar dapat diubah menjadi nilai r bertipe " pointer to char "; [...]. Dalam kedua kasus tersebut, hasilnya adalah penunjuk ke elemen pertama dari array. Konversi ini dianggap hanya jika terdapat tipe target penunjuk yang tepat secara eksplisit, dan bukan jika ada kebutuhan umum untuk mengubah nilai l ke nilai r. [Catatan: konversi ini tidak berlaku lagi . Lihat Lampiran D. ]
Jadi di C ++ 03, kodenya baik-baik saja (meskipun usang), dan memiliki perilaku yang jelas dan dapat diprediksi.
Di C ++ 11, blok itu tidak ada - tidak ada pengecualian untuk string literal yang diubah menjadi char*
, dan kode sama buruknya dengan int*
contoh yang baru saja saya berikan. Kompilator berkewajiban untuk mengeluarkan diagnostik, dan idealnya dalam kasus seperti ini yang merupakan pelanggaran yang jelas dari sistem tipe C ++, kita mengharapkan kompilator yang baik tidak hanya menyesuaikan dalam hal ini (misalnya dengan mengeluarkan peringatan) tetapi gagal sekaligus.
Kode idealnya tidak dapat dikompilasi - tetapi dilakukan pada gcc dan clang (saya berasumsi karena mungkin ada banyak kode di luar sana yang akan rusak dengan sedikit keuntungan, meskipun lubang sistem jenis ini tidak digunakan lagi selama lebih dari satu dekade). Kode tersebut berbentuk buruk, dan oleh karena itu tidak masuk akal untuk mempertimbangkan seperti apa perilaku kode tersebut. Tetapi mengingat kasus khusus ini dan riwayatnya sebelumnya diizinkan, saya tidak percaya itu menjadi peregangan yang tidak masuk akal untuk menafsirkan kode yang dihasilkan seolah-olah itu implisit const_cast
, sesuatu seperti:
const int arr[] = {1};
int *p = const_cast<int*>(arr); // OK, technically
Dengan itu, program lainnya baik-baik saja, karena Anda tidak pernah benar-benar menyentuhnya s
lagi. Membaca sebuah diciptakan- const
objek melalui non const
pointer ini sangat OK. Menulis sebuah diciptakan- const
objek melalui pointer tersebut adalah perilaku undefined:
std::cout << *p; // fine, prints 1
*p = 5; // will compile, but undefined behavior, which
// certainly qualifies as "unpredictable"
Karena tidak ada modifikasi melalui s
mana pun di kode Anda, program ini baik-baik saja di C ++ 03, seharusnya gagal dikompilasi di C ++ 11 tetapi tetap melakukannya - dan mengingat bahwa kompiler mengizinkannya, masih tidak ada perilaku yang tidak ditentukan di dalamnya † . Dengan kelonggaran bahwa kompiler masih [salah] menafsirkan aturan C ++ 03, saya tidak melihat apa pun yang akan menyebabkan perilaku "tidak dapat diprediksi". Tulislah s
, dan semua taruhan dibatalkan. Di C ++ 03 dan C ++ 11.
† Meskipun, sekali lagi, menurut definisi kode yang tidak benar tidak menghasilkan harapan perilaku yang wajar
‡ Kecuali tidak, lihat jawaban Matt McNabb