ฉันควรใช้ static_cast หรือ reinterpret_cast เมื่อทำการโมฆะ * ไปยังสิ่งใด


202

ทั้ง static_cast และ reinterpret_cast ดูเหมือนจะทำงานได้ดีในการคัดเลือกโมฆะ * ไปยังตัวชี้ประเภทอื่น มีเหตุผลที่ดีที่จะสนับสนุนอีกฝ่ายหรือไม่?


78
@anon เห็นได้ชัดว่าคุณไม่เคยทำงานกับ POSIX เธรดมาก่อน
user470379

7
@ user470379 ว้าว ... นั่นเป็นเหตุผลที่ฉันใช้คำถามนี้กับ SO! การสังเกตที่ดีเยี่ยม :-)
Ogre Psalm33

คำตอบ:


148

ใช้static_cast : มันเป็นเพี้ยนที่แคบที่สุดที่อธิบายการแปลงที่ทำที่นี่

มีความเข้าใจผิดว่าการใช้reinterpret_castจะเป็นการจับคู่ที่ดีกว่าเพราะมันหมายถึง“ ไม่สนใจความปลอดภัยของประเภทอย่างสมบูรณ์และเพิ่งส่งจาก A ถึง B”

reinterpret_castแต่นี้ไม่จริงอธิบายผลของการที่ ค่อนข้างreinterpret_castมีความหมายจำนวนมากสำหรับทุกสิ่งที่กล่าวว่า“ การแมปที่ดำเนินการโดยreinterpret_castเป็นการนำมาใช้งานที่กำหนดไว้” [5.2.10.3]

แต่ในกรณีเฉพาะของการคัดเลือกจากvoid*ไปยังT*การทำแผนที่นั้นถูกกำหนดไว้อย่างสมบูรณ์ตามมาตรฐาน กล่าวคือเพื่อกำหนดประเภทให้กับตัวชี้แบบไม่พิมพ์โดยไม่ต้องเปลี่ยนที่อยู่

static_castนี่คือเหตุผลที่จะชอบ

ยิ่งไปกว่านั้นและที่สำคัญกว่านั้นก็คือความจริงที่ว่าการใช้งานทุกครั้งreinterpret_castนั้นอันตรายอย่างยิ่งเพราะมันจะแปลงสิ่งใด ๆ ให้เป็นอย่างอื่น (สำหรับตัวชี้) ในขณะที่static_castมีข้อ จำกัด มากกว่าดังนั้นจึงเป็นการป้องกันที่ดีกว่า สิ่งนี้ได้ช่วยฉันจากข้อผิดพลาดที่ฉันพยายามบังคับให้ตัวชี้ประเภทหนึ่งไปยังอีกประเภทหนึ่งโดยไม่ตั้งใจ


8

นี่เป็นคำถามที่ยากมาก ในอีกด้านหนึ่ง Konrad สร้างจุดที่ยอดเยี่ยมเกี่ยวกับข้อกำหนด spec สำหรับreinterpret_castแม้ว่าในทางปฏิบัติมันอาจทำสิ่งเดียวกัน ในทางกลับกันถ้าคุณกำลังชี้ไปที่ประเภทตัวชี้ (ตามปกติเมื่อทำการจัดทำดัชนีในหน่วยความจำผ่านอักขระ * *, static_castจะสร้างข้อผิดพลาดของคอมไพเลอร์และคุณจะถูกบังคับให้ใช้reinterpret_castต่อไป

ในทางปฏิบัติฉันใช้reinterpret_castเพราะเป็นการอธิบายถึงเจตนาของการดำเนินการร่าย คุณสามารถสร้างกรณีให้ผู้ปฏิบัติงานรายอื่นเพื่อระบุตัวชี้ reinterprets เท่านั้น (ซึ่งรับประกันที่อยู่เดียวกันที่ส่งคืน) แต่ไม่มีหนึ่งในมาตรฐาน


6
" ผู้ประกอบการที่แตกต่างกันในการกำหนดตัวชี้ reinterprets เท่านั้น (ซึ่งรับประกันที่อยู่เดียวกันกลับมา) " กอด? ผู้ประกอบการนั่นคือ reinterpret_cast !
curiousguy

2
@cousguy ไม่จริงตามมาตรฐาน reinterpret_cast ไม่รับประกันว่าจะใช้ที่อยู่เดียวกัน เฉพาะเมื่อคุณ reinterpret_cast จากประเภทหนึ่งไปอีกประเภทหนึ่งแล้วกลับมาอีกครั้งคุณจะได้รับที่อยู่เดิมที่คุณเริ่มต้นด้วย
ClydeTheGhost

0

ฉันแนะนำให้ใช้นักแสดงที่อ่อนแอที่สุดที่เป็นไปได้เสมอ

reinterpret_castfloatอาจจะใช้ในการส่งตัวชี้ไปยัง ยิ่งการทำลายโครงสร้างมากขึ้นเท่าใดนัก

ในกรณีของchar*ฉันจะใช้นักแสดง c สไตล์จนกว่าเราจะมีบางอย่างreinterpret_pointer_castเพราะมันอ่อนแอและไม่มีอะไรเพียงพอ


2
" reinterpret_cast อาจถูกใช้เพื่อส่งพอยเตอร์ไปยังทุ่น " ไม่อย่างแน่นอน!
curiousguy

3
อาจเป็นได้float f = *reinterpret_cast<const float*>(&p);
Ben Voigt

2
@BenVoigt นั่นคือการคัดเลือกระหว่างพอยน์เตอร์; หนึ่งในนั้นเกิดขึ้นเป็นตัวชี้ลอย
nodakai

5
@BenVoigt "การแสดงออกทั้งหมด" ไม่ใช่นักแสดง การแสดงออกประกอบด้วย dereference ที่ใช้กับการโยน คุณอ้างว่าเป็นไปได้ที่จะส่งตัวชี้ไปfloatซึ่งเป็นเท็จ บรรยากาศการแสดงออกvoid **ไปconst float *แล้วใช้การดำเนินการ dereference (ซึ่งไม่หล่อ) การแปลงไปconst float * float
MM

2
@BenVoigt คุณเสนอรหัสนั้นเพื่อตอบสนองต่อคนที่ถามว่า "ฉันจะส่งอย่างไร ... " และเมื่อมีคนพูดว่ารหัสนั้นได้ปลดเปลื้องระหว่างตัวชี้ (ซึ่งเป็นเช่นนั้น) คุณพูดว่า "ไม่"
MM

-7

ความชอบส่วนบุคคลของฉันขึ้นอยู่กับความรู้เรื่องรหัสเช่นนี้:

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

หรือ

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

พวกเขาทั้งสองทำสิ่งเดียวกันในตอนท้าย แต่ static_cast ดูเหมือนจะเหมาะสมกว่าในแอพชั้นกลาง, สภาพแวดล้อมของแอปในขณะที่การตีความการส่งซ้ำนั้นดูเหมือนว่าสิ่งที่คุณจะเห็นใน IMHO ระดับต่ำกว่าไลบรารี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.