Чи слід використовувати static_cast або reinterpret_cast під час передавання порожнечі * до будь-якого


202

Як static_cast, так і reinterpret_cast, здається, добре спрацьовують для перенесення недійсних * до іншого типу вказівника. Чи є вагомі причини надати перевагу одне над іншим?


78
@anon Мабуть, ви ніколи до цього не працювали з потоками POSIX.
user470379

7
@ user470379 Нічого ... це саме та причина, що я приземлився з цього питання на SO! Відмінне спостереження :-).
Псалом Огре3333

Відповіді:


148

Використанняstatic_cast : саме вузький ролик точно описує те, що тут здійснюється перетворення.

Існує помилкова думка, що використання reinterpret_castбуде краще відповідати, оскільки це означає "повністю ігнорувати безпеку типу та просто передати з А на В".

Однак це насправді не описує ефект а reinterpret_cast. Скоріше, reinterpret_castмає низку значень, для всіх яких встановлено, що "відображення, яке виконується, визначено reinterpret_castреалізацією". [5.2.10.3]

Але в даному конкретному випадку виливки з void*до T*відображенню цілком добре визначено стандартом; а саме: призначити тип безтиповому вказівнику без зміни його адреси.

Це причина віддати перевагу static_cast.

Крім того, і, мабуть, важливішим є той факт, що будь-яке використання reinterpret_castпрямо небезпечно, оскільки воно перетворює що-небудь у будь-що інше насправді (для покажчиків), хоча воно static_castє набагато більш обмежуючим, забезпечуючи тим самим кращий рівень захисту. Це вже врятувало мене від помилок, де я випадково намагався примусити один тип вказівника до іншого.


8

Це складне питання. З одного боку, Конрад робить чудовий пункт щодо визначення специфікації для reinterpret_cast , хоча на практиці це, мабуть, робить те ж саме. З іншого боку, якщо ви робите кастинг між типами покажчиків (як це досить часто при індексації в пам'яті за допомогою char *, наприклад), static_cast призведе до помилки компілятора, і ви все одно будете змушені використовувати reinterpret_cast .

На практиці я використовую reinterpret_cast, тому що це більше описує наміри операції виклику. Ви, безумовно, можете зробити так, щоб інший оператор призначив лише вказівник реінтерпретації (що гарантувало повернення тієї ж адреси), але в стандарті немає жодної.


6
" інший оператор для призначення лише вказівника реінтерпретується (що гарантує повернення тієї ж адреси) " Обійми? Цей оператор є reinterpret_cast !
curiousguy

2
@curiousguy Не вірно згідно стандарту. reinterpret_cast НЕ гарантує використання тієї самої адреси. Тільки те, що якщо ви переймете_переміщення з одного типу в інший і знову повернетеся , ви отримаєте ту саму адресу, з якою ви почали.
ClydeTheGhost

0

Я пропоную завжди використовувати найслабший акторський склад.

reinterpret_castможе використовуватися для наведення покажчика на a float. Чим більше в структурі складів, тим більше уваги потребує його використання.

У випадку char*я б застосував c-style casting, поки у нас його немає reinterpret_pointer_cast, тому що він слабший і нічого іншого недостатньо.


2
" reinterpret_cast може використовуватися для наведення покажчика на поплавок. " Звичайно, ні!
curiousguy

3
Напевноfloat f = *reinterpret_cast<const float*>(&p);
Бен Войгт

2
@BenVoigt - це передача між покажчиками; одна з них сталася поплавковою вказівкою.
нодакай

5
@BenVoigt, але "весь вираз" не є акторським складом. Вираз складається з розвідки, застосованої до акторського складу. Ви стверджували, що можна закидати покажчик на float, що хибно. Вираз закидання void **до const float *, а потім використовує операцію разименованія (який не є виливок), щоб конвертувати const float *в float.
ММ

2
@BenVoigt ви запропонували цей код у відповідь на запитання "Як я можу подати ...", а потім, коли хтось сказав, що код кидається між покажчиками (що це робить), ви сказали "Ні"
ММ

-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 бібліотеці нижчого рівня.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.