Haruskah saya menggunakan static_cast atau reinterpret_cast ketika melakukan void * untuk apa pun

202

Baik static_cast dan reinterpret_cast tampaknya berfungsi dengan baik untuk membuang void * ke jenis pointer lain. Apakah ada alasan bagus untuk lebih menyukai yang satu dari yang lain?

Andy
sumber
78
@anon Rupanya Anda belum pernah bekerja dengan utas POSIX sebelumnya.
user470379
7
@ user470379 Wow ... itulah alasan saya mendarat di pertanyaan ini di SO! Pengamatan yang sangat baik :-).
Ogre Psalm33

Jawaban:

148

Gunakanstatic_cast : ini adalah pemeran tersempit yang menggambarkan dengan tepat konversi apa yang dibuat di sini.

Ada kesalahpahaman bahwa menggunakan reinterpret_castakan menjadi pertandingan yang lebih baik karena itu berarti "sama sekali mengabaikan keselamatan jenis dan hanya melemparkan dari A ke B".

Namun, ini sebenarnya tidak menggambarkan efek dari a reinterpret_cast. Sebaliknya, reinterpret_castmemiliki sejumlah makna, yang kesemuanya berpendapat bahwa "pemetaan yang dilakukan oleh reinterpret_castdidefinisikan-implementasi." [5.2.10.3]

Tetapi dalam kasus khusus casting dari void*ke T*pemetaan sepenuhnya didefinisikan dengan baik oleh standar; yaitu, untuk menetapkan tipe ke pointer tanpa typeless tanpa mengubah alamatnya.

Ini adalah alasan untuk memilih static_cast.

Selain itu, dan bisa dibilang lebih penting, adalah kenyataan bahwa setiap penggunaan reinterpret_castbenar-benar berbahaya karena mengubah apa pun menjadi hal lain benar-benar (untuk petunjuk), sementara static_castjauh lebih ketat, sehingga memberikan tingkat perlindungan yang lebih baik. Ini sudah menyelamatkan saya dari bug di mana saya tidak sengaja mencoba memaksa satu jenis pointer ke yang lain.

Konrad Rudolph
sumber
8

Ini adalah pertanyaan yang sulit. Di satu sisi, Konrad membuat poin yang sangat baik tentang definisi spesifikasi untuk reinterpret_cast , meskipun dalam praktiknya mungkin melakukan hal yang sama. Di sisi lain, jika Anda melakukan casting di antara tipe pointer (seperti yang biasa terjadi saat pengindeksan dalam memori melalui char *, misalnya), static_cast akan menghasilkan kesalahan kompiler dan Anda akan dipaksa untuk menggunakan reinterpret_cast pula.

Dalam praktiknya saya menggunakan reinterpret_cast karena lebih deskriptif tentang maksud operasi pemeran. Anda tentu bisa membuat kasus untuk operator yang berbeda untuk menunjuk penafsiran ulang pointer saja (yang menjamin alamat yang sama dikembalikan), tetapi tidak ada satu pun dalam standar.

Nick
sumber
6
" operator yang berbeda untuk menunjuk penafsiran ulang pointer saja (yang menjamin alamat yang sama dikembalikan) " Hug? Operator itu reinterpret_cast !
curiousguy
2
@curiousguy Tidak benar sesuai dengan standar. reinterpret_cast TIDAK menjamin bahwa alamat yang sama digunakan. Hanya itu jika Anda menginterpretasi ulang dari satu jenis ke yang lain dan kemudian kembali lagi , Anda akan mendapatkan kembali alamat yang sama dengan yang Anda mulai.
ClydeTheGhost
0

Saya sarankan menggunakan pemain terlemah yang mungkin selalu.

reinterpret_castdapat digunakan untuk melemparkan pointer ke a float. Semakin banyak pemecah struktur yang dilemparkan, semakin banyak perhatian yang dibutuhkan.

Dalam hal char*, saya akan menggunakan pemeran c-style, sampai kita memiliki beberapa reinterpret_pointer_cast, karena itu lebih lemah dan tidak ada lagi yang cukup.

Pavel Radzivilovsky
sumber
2
" reinterpret_cast dapat digunakan untuk mengarahkan pointer ke float. " Tentu saja tidak!
curiousguy
3
Mungkinfloat f = *reinterpret_cast<const float*>(&p);
Ben Voigt
2
@ BenVoigt Itu adalah casting di antara pointer; salah satunya adalah penunjuk float.
nodakai
5
@BenVoigt "seluruh ekspresi" bukan gips. Ekspresi terdiri dari dereferensi yang diterapkan pada pemain. Anda mengklaim bahwa itu mungkin untuk mengarahkan pointer float, yang salah. Ekspresi gips void **untuk const float *, dan kemudian menggunakan operasi dereference (yang TIDAK gips), untuk mengkonversi const float *ke float.
MM
2
@BenVoigt Anda menawarkan kode itu sebagai respons terhadap seseorang yang bertanya "Bagaimana cara saya membuang ...", dan kemudian ketika seseorang mengatakan bahwa kode tersebut melemparkan di antara pointer (yang memang demikian), Anda berkata "Tidak"
MM
-7

Preferensi pribadi saya didasarkan pada literasi kode seperti ini:

void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();

atau

typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();

Mereka berdua melakukan hal yang sama pada akhirnya, tetapi static_cast tampaknya lebih tepat di lingkungan aplikasi menengah, sementara menafsirkan kembali para pemain sepertinya lebih seperti yang Anda lihat di IMHO perpustakaan tingkat rendah.

Robert Gould
sumber