Dalam C, tidak perlu untuk melemparkan void *
ke tipe pointer lain, itu selalu dipromosikan dengan aman. Namun, dalam C ++, ini tidak terjadi. Misalnya,
int *a = malloc(sizeof(int));
bekerja di C, tetapi tidak di C ++. (Catatan: Saya tahu bahwa Anda tidak boleh menggunakan malloc
C ++, atau dalam hal ini new
, dan lebih baik memilih smart pointer dan / atau STL; ini diminta murni karena penasaran) Mengapa standar C ++ tidak mengizinkan pemeran tersirat ini, sedangkan standar C tidak?
c++
language-features
wolfPack88
sumber
sumber
long *a = malloc(sizeof(int));
Ups, seseorang lupa mengubah hanya satu jenis!sizeof(*a)
sebagai gantinya.malloc
tidak dapat mengembalikan pointer ke tipe yang dialokasikan.new
adalah C ++ mengembalikan pointer ke tipe yang dialokasikan, jadi kode C ++ yang ditulis dengan benar tidak akan pernah adavoid *
untuk dilemparkan.void
, C tidak . Ketika kata kunci / ide itu ditambahkan ke C, mereka mengubahnya sesuai dengan kebutuhan C. Itu tidak lama setelah tipe pointer mulai diperiksa sama sekali . Lihat apakah Anda dapat menemukan pamflet deskripsi K&R C online, atau salinan vintage dari teks pemrograman C seperti C Primer Waite Group . ANSI C penuh, fitur yang didukung atau diilhami oleh C ++, dan K&R C jauh lebih sederhana. Jadi itu lebih benar bahwa C ++ diperpanjang C seperti yang ada pada saat itu, dan C yang Anda tahu dilucuti dari C ++.Jawaban:
Karena konversi tipe implisit biasanya tidak aman, dan C ++ mengambil posisi yang lebih aman untuk mengetik daripada C.
C biasanya akan memungkinkan konversi implisit, bahkan jika sebagian besar kemungkinan konversi adalah kesalahan. Itu karena C mengasumsikan bahwa programmer tahu persis apa yang mereka lakukan, dan jika tidak, itu adalah masalah programmer, bukan masalah kompiler.
C ++ biasanya akan melarang hal-hal yang berpotensi menjadi kesalahan, dan mengharuskan Anda untuk secara eksplisit menyatakan niat Anda dengan tipe pemain. Itu karena C ++ sedang mencoba untuk menjadi ramah-programmer.
Anda mungkin bertanya mengapa itu ramah ketika sebenarnya mengharuskan Anda untuk mengetik lebih banyak.
Nah, Anda lihat, setiap baris kode tertentu, dalam program apa pun, dalam bahasa pemrograman apa pun, umumnya akan dibaca lebih banyak daripada yang akan ditulis (*). Jadi, kemudahan membaca jauh lebih penting daripada kemudahan menulis. Dan ketika membaca, memiliki konversi yang berpotensi tidak aman menonjol melalui pemeran tipe eksplisit membantu untuk memahami apa yang sedang terjadi dan untuk memiliki tingkat kepastian tertentu bahwa apa yang terjadi sebenarnya apa yang dimaksudkan untuk terjadi.
Selain itu, ketidaknyamanan karena harus mengetikkan pemeran eksplisit adalah sepele dibandingkan dengan ketidaknyamanan berjam-jam pemecahan masalah untuk menemukan bug yang disebabkan oleh tugas yang salah yang bisa Anda peringatkan, tetapi tidak pernah dilakukan.
(*) Idealnya hanya akan ditulis satu kali, tetapi akan dibaca setiap kali seseorang perlu memeriksanya untuk menentukan kesesuaiannya untuk digunakan kembali, dan setiap kali ada pemecahan masalah yang terjadi, dan setiap kali seseorang perlu menambahkan kode di dekatnya, dan kemudian setiap kali ada pemecahan masalah kode terdekat, dan sebagainya. Ini benar dalam semua kasus kecuali untuk skrip "tulis-sekali, jalankan, lalu buang", dan karenanya tidak mengherankan bahwa sebagian besar bahasa skrip memiliki sintaksis yang memfasilitasi kemudahan menulis dengan mengabaikan sepenuhnya untuk kemudahan membaca. Pernah berpikir bahwa perl benar-benar tidak dapat dipahami? Anda tidak sendiri. Pikirkan bahasa-bahasa seperti bahasa "hanya-tulis".
sumber
void*
yang lebih aman di C ++, karena dengan cara fitur OOP tertentu diimplementasikan dalam C ++, pointer ke objek yang sama mungkin memiliki nilai yang berbeda tergantung pada jenis pointer.Inilah yang dikatakan Stroustrup :
Dia kemudian menunjukkan contoh bagaimana kekosongan * bisa berbahaya dan mengatakan:
Akhirnya, ia mencatat:
Dia membahas lebih detail tentang hal ini dalam Desain dan Evolusi C ++ .
Jadi, jawabannya adalah: Perancang bahasa percaya bahwa itu adalah pola yang tidak aman, dan membuatnya ilegal dan menyediakan cara alternatif untuk mencapai apa pola yang biasanya digunakan.
sumber
malloc
contoh, perlu dicatat bahwamalloc
(tentu saja) tidak akan memanggil konstruktor, jadi jika itu adalah tipe kelas yang Anda alokasikan memori, dapat secara implisit dilemparkan ke tipe kelas akan menyesatkan.Itu selalu dipromosikan, ya, tapi hampir tidak aman .
C ++ menonaktifkan perilaku ini karena ia mencoba untuk memiliki sistem tipe yang lebih aman daripada C, dan perilaku ini tidak aman.
Pertimbangkan secara umum 3 pendekatan ini untuk mengetik konversi:
Ya, saya jelek dan merupakan penghalang praktis untuk menyelesaikan sesuatu, tetapi mungkin benar-benar digunakan di tempat yang membutuhkan perhatian besar. C secara kasar memilih 2, yang lebih mudah diimplementasikan, dan C ++ untuk 3, yang lebih sulit diterapkan tetapi lebih aman.
sumber
Menurut definisi, Void pointer dapat menunjuk ke apa saja. Setiap pointer dapat dikonversi menjadi void pointer dan dengan demikian, Anda akan dapat mengkonversi kembali sampai pada nilai yang sama persis. Namun, pointer ke tipe lain mungkin memiliki kendala, seperti batasan perataan. Sebagai contoh, bayangkan sebuah arsitektur di mana karakter dapat menempati alamat memori apa pun tetapi bilangan bulat harus dimulai pada batas alamat yang genap. Dalam arsitektur tertentu, pointer integer bahkan dapat menghitung 16, 32 atau 64 bit pada suatu waktu sehingga char * mungkin sebenarnya memiliki kelipatan nilai numerik int * sambil menunjuk ke tempat yang sama dalam memori. Dalam hal ini, mengkonversi dari void * sebenarnya akan membulatkan bit yang tidak dapat dipulihkan dan karenanya tidak dapat dibalik.
Sederhananya, void pointer dapat menunjuk ke apa saja, termasuk hal-hal yang mungkin tidak dapat ditunjukkan oleh pointer lain. Dengan demikian, konversi ke void pointer aman tetapi tidak sebaliknya.
sumber