Похоже, что static_cast и reinterpret_cast работают нормально для приведения void * к другому типу указателя. Есть ли веская причина отдать предпочтение одному над другим?
Похоже, что static_cast и reinterpret_cast работают нормально для приведения void * к другому типу указателя. Есть ли веская причина отдать предпочтение одному над другим?
Ответы:
Использование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
может использоваться для приведения указателя к float
. Чем сильнее разрушается структура актерского состава, тем больше внимания требует его использование.
В случае char*
я бы использовал приведение в стиле c, пока у нас их не будет 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.