Pertanyaan Ketika mengkonversi pointer kosong ke tipe pointer tertentu, simbol casting mana yang lebih baik, static_cast atau reinterpret_cast? [duplikat]


Kemungkinan Duplikat:
Haruskah saya menggunakan static_cast atau reinterpret_cast saat casting void * pada apa pun 

Dalam program ini saya punya void * sebagai parameter dan ingin mentransmisikannya ke tipe tertentu. Tapi saya tidak tahu "lambang casting" mana yang digunakan. Kedua static_cast atau reinterpret_cast kerja. Mana yang lebih baik? Yang mana yang direkomendasikan oleh Standar C ++?

typedef struct
{
    int a;
}A, *PA;

int foo(void* a)                // the real type of a is A*
{
    A* pA = static_cast<A*>(a); // or A* pA = reinterpret_cast<A*>(a);?
    return pA->a;
}

Disini adalah

A* pA = static_cast<A*>(a);

atau

A* pA = reinterpret_cast<A*>(a);

lebih tepat?


32
2018-02-16 07:22


asal


Jawaban:


Itu static_cast lebih tepat untuk mengonversi a void* ke penunjuk dari beberapa jenis lainnya.

static_cast adalah pilihan utama ketika ada konversi yang alami dan intuitif antara dua jenis yang tidak selalu dijamin bekerja saat runtime. Misalnya, Anda bisa menggunakan static_cast untuk mengonversi pointer kelas dasar ke pointer kelas turunan, yang merupakan konversi yang masuk akal dalam beberapa kasus tetapi tidak dapat diverifikasi hingga waktu proses. Demikian pula, Anda bisa menggunakannya static_cast untuk mengonversi dari int ke a char, yang terdefinisi dengan baik tetapi dapat menyebabkan hilangnya presisi ketika dieksekusi.

reinterpret_cast, di sisi lain, adalah operator casting yang dirancang untuk melakukan konversi yang pada dasarnya tidak aman atau tidak portabel. Misalnya, Anda bisa menggunakan reinterpret_cast untuk mengkonversi dari void * ke sebuah int, yang akan berfungsi dengan benar jika sistem Anda kebetulan ada sizeof (void*) ≤ sizeof (int). Anda juga bisa menggunakan reinterpret_cast untuk mengonversi float* ke sebuah int* atau sebaliknya, yang merupakan platform khusus karena representasi tertentu dari floats dan ints tidak dijamin memiliki kesamaan satu sama lain.

Singkatnya, jika Anda pernah menemukan diri Anda melakukan konversi di mana para pemain secara logis berarti tetapi mungkin tidak selalu berhasil pada saat runtime, hindari reinterpret_cast. static_cast adalah pilihan yang baik jika Anda memiliki pengetahuan awal bahwa pemain akan bekerja pada saat runtime, dan berkomunikasi dengan compiler "Saya tahu bahwa ini mungkin tidak berfungsi, tapi setidaknya itu masuk akal dan saya punya alasan untuk percaya itu akan benar. lakukan hal yang benar saat runtime. " Compiler kemudian dapat memeriksa apakah gips berada di antara jenis terkait, melaporkan kesalahan waktu kompilasi jika ini tidak terjadi. Menggunakan reinterpret_cast untuk melakukan ini dengan konversi pointer sepenuhnya melewati pemeriksaan keamanan kompilasi-waktu.

Ada beberapa keadaan di mana Anda mungkin ingin menggunakan dynamic_cast bukannya a static_cast, tetapi ini kebanyakan melibatkan pemeran dalam hirarki kelas dan (hanya jarang) perhatian langsung void*.

Adapun yang lebih disukai oleh spec, tidak terlalu disebutkan sebagai "yang tepat untuk digunakan" (atau setidaknya, saya tidak ingat salah satu dari mereka disebutkan dengan cara ini.) Namun, saya pikir spec ingin Anda menggunakan static_cast lebih reinterpret_cast. Misalnya, saat menggunakan cast gaya C, seperti pada

A* ptr = (A*) myVoidPointer;

Urutan operator pengecoran yang mencoba selalu mencoba menggunakan static_cast sebelum reinterpret_cast, yang merupakan perilaku yang Anda inginkan sejak itu reinterpret_cast tidak dijamin portabel.


45
2018-02-16 07:28



Menggunakan static_cast untuk ini. Hanya dalam kasus langka yang jarang terjadi ketika tidak ada cara lain yang digunakan reinterpret_cast.


1
2018-02-16 07:24



Jika Anda mentransmisikan sepanjang hierarki kelas, gunakan dynamic_cast - ini memeriksa untuk memastikan bahwa objek yang sebenarnya kompatibel dengan jenis yang Anda casting.


1
2018-02-16 07:28



Anda mungkin memperoleh itu void* dengan konversi implisit, jadi Anda harus menggunakannya static_cast karena paling dekat dengan konversi implisit.


0
2018-02-16 07:27



reinterpret_cast akan secara paksa mengubah void* ke tipe data target. Ini tidak menjamin keamanan dan program Anda mungkin macet karena objek yang mendasarinya bisa apa saja.

Untuk mantan, Anda bisa mengetik sebuah myclass* untuk void* lalu gunakan reinterpret_cast untuk mengubahnya menjadi yourclass* yang mungkin memiliki tata letak yang sama sekali berbeda.

Jadi lebih baik dan disarankan untuk digunakan static_cast


-1
2018-02-16 07:28



Bukan keduanya. Mengapa Anda melewati pointer untuk membatalkan di tempat pertama? Dalam C itu cukup umum karena kurangnya alternatif, tetapi di C ++ hampir ada tak pernah alasan untuk melakukan hal semacam itu.

Edit: @Dan O meningkatkan kemungkinan menggunakan cast untuk meminimalkan kode yang dihasilkan. Bagi siapa saja yang tidak mengerti apa yang dibicarakannya, pertimbangkan sesuatu seperti itu std::vector - ketika Anda mendefinisikan (misalnya) sebuah std::vector<A *> dan sebuah std::vector<B *>, biasanya Anda akan berakhir dengan kode yang benar-benar terpisah untuk masing-masing meskipun keduanya hanya menyimpan pointer, sehingga mereka dapat berbagi kode yang sama. Adalah mungkin untuk menyiasati itu dengan mendefinisikan wadah yang hanya berlaku void *s, dan cast kembali ke jenis yang benar ketika Anda mengambil item dari wadah.

Pertama-tama, ini biasanya merupakan pengoptimalan prematur yang terbaik (dan sering dapat berubah menjadi pesimisme). Meskipun demikian, ada kalanya itu masuk akal. Namun, ketika Anda ingin membatasi cast satu tempat, tetapi menciptakan front-end templated ke wadah pseudo-generic void *s:

template <class T>
pointer_container {
    std::vector <void *> data;
public:
    T *operator[](size_t index) { return static_cast<T *>(data[index]); }
};

Sekarang, memang benar bahwa kita sekarang memiliki pemain. Dan ya, untuk memberikan jawaban langsung ke pertanyaan awal, a static_cast adalah yang tepat untuk digunakan dalam situasi seperti ini.

Kembali pada hari-hari MS-DOS (untuk satu contoh) kode seperti ini cukup umum. Hari ini, bagaimanapun, gaya kode ini sama sekali tidak ada gunanya.

Sekarang, OP mengatakan dia terjebak dengan antarmuka tetap, dan itu tugasnya untuk mengimplementasikannya. Saya tidak tahu di mana dia bekerja atau dengan siapa dia bekerja, dan saya belum melihat sisa kode yang bekerja dengan ini, jadi itu benar bahwa saya tidak bisa mengatakannya yakin bahwa apa yang mereka lakukan tidak dirancang dengan baik dan harus diubah. OTOH, berdasarkan pengalaman masa lalu saya, saya kira kemungkinan itu adalah masalahnya paling sedikit 99%. Dengan demikian, saya berdiri dengan jawaban asli saya. Jawaban yang diposting yang baru saja mengatakan "static_cast", dengan tidak ada tentang menghindari pemain adalah orang-orang yang benar-benar tidak membantu. Meskipun hampir tidak mungkin para pemain sangat tidak dapat dihindari, hanya dengan asumsi bahwa itu dibenarkan adalah salah reaksi dan jawaban yang buruk.

Saya akan melangkah lebih jauh: jika pertanyaan tentang casting yang gagal memberikan bukti tentang mengapa pemain tersebut tidak dapat dihindari, hanya saran bahwa siapa pun harus mempertimbangkan "baik" sama sekali adalah saran untuk menghilangkan pemain sepenuhnya. Saya t mungkin (pada kesempatan langka) ternyata pemeran tidak dapat dihindari - tetapi itu jelas pengecualian, bukan aturannya.


-1
2018-02-16 07:28