Apakah ada penggunaan yang sah void*
di C ++? Atau apakah ini diperkenalkan karena C memilikinya?
Sekadar rekap pikiran saya:
Masukan : Jika kita ingin mengizinkan beberapa jenis masukan, kita dapat membebani fungsi dan metode, sebagai alternatif kita dapat menentukan kelas dasar umum, atau templat (terima kasih telah menyebutkan ini dalam jawaban). Dalam kedua kasus, kode menjadi lebih deskriptif dan lebih sedikit rawan kesalahan (asalkan kelas dasar diimplementasikan dengan cara yang waras).
Hasil : Saya tidak dapat memikirkan situasi apa pun di mana saya lebih suka menerima void*
daripada sesuatu yang berasal dari kelas dasar yang dikenal.
Hanya untuk memperjelas apa yang saya maksud: Saya tidak secara khusus menanyakan apakah ada kasus penggunaan void*
, tetapi jika ada kasus di mana void*
adalah pilihan terbaik atau satu-satunya yang tersedia. Yang telah dijawab dengan sempurna oleh beberapa orang di bawah ini.
variant
,any
, ditandai serikat. Apa pun yang dapat memberi tahu Anda jenis konten yang sebenarnya dan lebih aman untuk digunakan.Jawaban:
void*
setidaknya diperlukan sebagai hasil dari::operator new
(juga setiapoperator new
...) dan darimalloc
dan sebagai argumennew
operator penempatan .void*
dapat dianggap sebagai supertipe umum dari setiap jenis penunjuk. Jadi ini tidak berarti penunjuk kevoid
, tapi penunjuk ke apapun.BTW, jika Anda ingin menyimpan beberapa data untuk beberapa variabel global yang tidak terkait, Anda dapat menggunakan beberapa
std::map<void*,int> score;
kemudian, setelah mendeklarasikan globalint x;
dandouble y;
danstd::string s;
melakukanscore[&x]=1;
danscore[&y]=2;
danscore[&z]=3;
memset
menginginkan avoid*
alamat (yang paling umum)Selain itu, sistem POSIX memiliki dlsym dan jenis kembaliannya jelas seharusnya
void*
sumber
char *
juga. Mereka sangat dekat dalam aspek ini, meski artinya sedikit berbeda.C++
tertulis diC++
sini adalah alasan yang cukup untuk dimilikivoid*
. Harus menyukai situs ini. Ajukan satu pertanyaan, belajar banyak.void*
tipe. Semua fungsi perpustakaan standar digunakanchar*
Ada beberapa alasan untuk menggunakan
void*
, 3 alasan paling umum:void*
di antarmukanyaDalam urutan terbalik, menunjukkan memori yang tidak diketik dengan
void*
(3) sebagai gantichar*
(atau varian) membantu mencegah aritmatika penunjuk yang tidak disengaja; hanya ada sedikit operasi yang tersediavoid*
sehingga biasanya memerlukan casting sebelum berguna. Dan tentu saja,char*
tidak ada masalah dengan aliasing.Type-erasure (2) masih digunakan di C ++, bersama dengan template atau tidak:
std::function
Dan jelas, ketika antarmuka yang Anda tangani menggunakan
void*
(1), Anda tidak punya banyak pilihan.sumber
Oh ya. Bahkan di C ++ terkadang kita pergi dengan
void *
daripadatemplate<class T*>
karena terkadang kode tambahan dari ekspansi template terlalu berat.Biasanya saya akan menggunakannya sebagai implementasi aktual dari tipe, dan tipe template akan mewarisi darinya dan membungkus gips.
Selain itu, pengalokasi slab khusus (implementasi baru operator) harus digunakan
void *
. Ini adalah salah satu alasan mengapa g ++ menambahkan ekstensi yang mengizinkan penunjuk aritmatikvoid *
seolah-olah berukuran 1.sumber
struct wrapper_base {}; template<class T> struct wrapper : public wrapper_base {T val;} typedef wrapper* like_void_ptr;
adalah void - * - minimal simulator yang menggunakan template.Benar.
Ini sebagian benar: bagaimana jika Anda tidak bisa mendefinisikan kelas basis umum, antarmuka atau serupa? Untuk menentukan mereka, Anda harus memiliki akses ke kode sumber, yang seringkali tidak memungkinkan.
Anda tidak menyebutkan template. Namun, template tidak dapat membantu Anda dengan polimorfisme: template tersebut bekerja dengan tipe statis yaitu yang dikenal pada waktu kompilasi.
void*
dapat dianggap sebagai penyebut umum terendah. Di C ++, Anda biasanya tidak membutuhkannya karena (i) Anda tidak dapat melakukan banyak hal dengannya dan (ii) hampir selalu ada solusi yang lebih baik.Lebih jauh lagi, Anda biasanya akan mengubahnya menjadi jenis beton lainnya. Itulah mengapa
char *
biasanya lebih baik, meskipun ini mungkin menunjukkan bahwa Anda mengharapkan string gaya-C, daripada blok data murni. Itulah mengapavoid*
lebih baik darichar*
itu, karena memungkinkan transmisi implisit dari tipe penunjuk lainnya.Anda seharusnya menerima beberapa data, bekerja dengannya dan menghasilkan keluaran; untuk mencapainya, Anda perlu mengetahui data yang sedang Anda kerjakan, jika tidak, Anda memiliki masalah lain yang bukan merupakan masalah yang awalnya Anda selesaikan. Banyak bahasa tidak memiliki
void*
dan tidak bermasalah dengan itu, misalnya.Penggunaan sah lainnya
Saat mencetak alamat penunjuk dengan fungsi seperti
printf
penunjuk harus memilikivoid*
tipe dan, oleh karena itu, Anda mungkin memerlukan cast kevoid
*sumber
Ya, itu sama berguna seperti hal lain dalam bahasa ini.
Sebagai contoh, Anda dapat menggunakannya untuk menghapus jenis kelas yang dapat Anda transmisikan secara statis ke jenis yang tepat saat diperlukan, untuk memiliki antarmuka yang minimal dan fleksibel.
Dalam bahwa respon ada contoh penggunaan yang seharusnya memberi Anda ide.
Saya salin dan tempel di bawah ini demi kejelasan:
class Dispatcher { Dispatcher() { } template<class C, void(C::*M)() = C::receive> static void invoke(void *instance) { (static_cast<C*>(instance)->*M)(); } public: template<class C, void(C::*M)() = &C::receive> static Dispatcher create(C *instance) { Dispatcher d; d.fn = &invoke<C, M>; d.instance = instance; return d; } void operator()() { (fn)(instance); } private: using Fn = void(*)(void *); Fn fn; void *instance; };
Jelas, ini hanya salah satu dari sekumpulan kegunaan
void*
.sumber
Berinteraksi dengan fungsi perpustakaan eksternal yang mengembalikan sebuah pointer. Ini satu untuk aplikasi Ada.
extern "C" { void* ada_function();} void* m_status_ptr = ada_function();
Ini mengembalikan pointer ke apapun yang Ada ingin beritahukan kepada Anda. Anda tidak perlu melakukan sesuatu yang mewah, Anda dapat memberikannya kembali kepada Ada untuk melakukan hal berikutnya. Faktanya, menguraikan pointer Ada di C ++ bukanlah hal yang sepele.
sumber
auto
sebagai gantinya dalam kasus ini? Dengan asumsi bahwa tipe tersebut diketahui pada waktu kompilasi.Singkatnya, C ++ sebagai bahasa yang ketat (tidak memperhitungkan peninggalan C seperti malloc () ) membutuhkan void * karena tidak memiliki induk umum dari semua jenis yang mungkin. Berbeda dengan ObjC, misalnya yang memiliki objek .
sumber
malloc
dannew
keduanya kembalivoid *
, jadi Anda akan memerlukannya jika meskipun ada kelas objek di C ++operator new()
kembalivoid *
, tetapinew
ekspresi tidakint
2. jika itu adalah EBC non-virtual, lalu apa bedanya denganvoid*
?Hal pertama yang muncul di benak saya (yang saya curigai adalah kasus konkret dari beberapa jawaban di atas) adalah kemampuan untuk meneruskan instance objek ke threadproc di Windows.
Saya punya beberapa kelas C ++ yang perlu melakukan ini, mereka memiliki implementasi utas pekerja dan parameter LPVOID di API CreateThread () mendapatkan alamat implementasi metode statis di kelas sehingga utas pekerja dapat melakukan pekerjaan dengan contoh spesifik kelas. Transmisi statis sederhana di threadproc menghasilkan instance untuk digunakan, yang memungkinkan setiap objek yang dibuat memiliki thread pekerja dari implementasi metode statis tunggal.
sumber
Dalam kasus multiple inheritance, jika Anda perlu mendapatkan pointer ke byte pertama dari potongan memori yang ditempati oleh suatu objek, Anda dapat
dynamic_cast
melakukannyavoid*
.sumber