Як static_cast, так і reinterpret_cast, здається, добре спрацьовують для перенесення недійсних * до іншого типу вказівника. Чи є вагомі причини надати перевагу одне над іншим?
Як static_cast, так і reinterpret_cast, здається, добре спрацьовують для перенесення недійсних * до іншого типу вказівника. Чи є вагомі причини надати перевагу одне над іншим?
Відповіді:
Використанняstatic_cast : саме вузький ролик точно описує те, що тут здійснюється перетворення.
Існує помилкова думка, що використання reinterpret_castбуде краще відповідати, оскільки це означає "повністю ігнорувати безпеку типу та просто передати з А на В".
Однак це насправді не описує ефект а reinterpret_cast. Скоріше, reinterpret_castмає низку значень, для всіх яких встановлено, що "відображення, яке виконується, визначено reinterpret_castреалізацією". [5.2.10.3]
Але в даному конкретному випадку виливки з void*до T*відображенню цілком добре визначено стандартом; а саме: призначити тип безтиповому вказівнику без зміни його адреси.
Це причина віддати перевагу static_cast.
Крім того, і, мабуть, важливішим є той факт, що будь-яке використання reinterpret_castпрямо небезпечно, оскільки воно перетворює що-небудь у будь-що інше насправді (для покажчиків), хоча воно static_castє набагато більш обмежуючим, забезпечуючи тим самим кращий рівень захисту. Це вже врятувало мене від помилок, де я випадково намагався примусити один тип вказівника до іншого.
Це складне питання. З одного боку, Конрад робить чудовий пункт щодо визначення специфікації для reinterpret_cast , хоча на практиці це, мабуть, робить те ж саме. З іншого боку, якщо ви робите кастинг між типами покажчиків (як це досить часто при індексації в пам'яті за допомогою char *, наприклад), static_cast призведе до помилки компілятора, і ви все одно будете змушені використовувати reinterpret_cast .
На практиці я використовую reinterpret_cast, тому що це більше описує наміри операції виклику. Ви, безумовно, можете зробити так, щоб інший оператор призначив лише вказівник реінтерпретації (що гарантувало повернення тієї ж адреси), але в стандарті немає жодної.
reinterpret_cast !
Я пропоную завжди використовувати найслабший акторський склад.
reinterpret_castможе використовуватися для наведення покажчика на a float. Чим більше в структурі складів, тим більше уваги потребує його використання.
У випадку char*я б застосував c-style casting, поки у нас його немає reinterpret_pointer_cast, тому що він слабший і нічого іншого недостатньо.
float f = *reinterpret_cast<const float*>(&p);
float, що хибно. Вираз закидання void **до const float *, а потім використовує операцію разименованія (який не є виливок), щоб конвертувати const float *в float.
Мої особисті переваги засновані на кодовій грамотності на зразок цього:
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 бібліотеці нижчого рівня.