Должен ли я использовать static_cast или reinterpret_cast при запуске void * на все

Как static_cast, так и reinterpret_cast, похоже, отлично работают для литья void * в другой тип указателя. Есть ли веская причина, чтобы поддержать друг друга?

Ответ 1

Использовать static_cast: это самый узкий актер, который точно описывает, какое преобразование сделано здесь.

Это неправильное представление о том, что использование reinterpret_cast было бы лучшим совпадением, потому что это означает "полностью игнорировать безопасность типов и просто отбрасывать от A до B".

Однако это фактически не описывает эффект reinterpret_cast. Скорее, reinterpret_cast имеет ряд значений, для всех которых выполняется, что "отображение, выполняемое reinterpret_cast, определяется реализацией". [5.2.10.3]

Но в частном случае отбрасывания от void* до T* отображение полностью определяется стандартом; а именно, присваивать тип беззнаменному указателю без изменения его адреса.

Это повод предпочесть static_cast.

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

Ответ 2

Это сложный вопрос. С одной стороны, Konrad делает отличную оценку определения spec для reinterpret_cast, хотя на практике это, вероятно, делает то же самое. С другой стороны, если вы используете разные типы указателей (как это обычно бывает при индексировании в памяти с помощью char *), static_cast генерирует ошибку компилятора, и вы будете будет вынужден использовать reinterpret_cast.

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

Ответ 3

Я предлагаю использовать максимально возможный листинг.

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

В случае char *, я бы использовал c-style cast, пока у нас не будет некоторого reinterpret_pointer_cast, потому что он слабее и ничего больше не достаточно.

Ответ 4

Мои личные предпочтения основаны на грамотности кода следующим образом:

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.