Является ли reinterpret cast единственным допустимым использованием reinterpret cast?


Недавно я узнал, что стандарт C++ содержит "строгие правила псевдонимирования", которые запрещают ссылаться на одно и то же место памяти через переменные разных типов.

Однако стандарт позволяет типам char юридически псевдонимировать любой другой тип. Означает ли это, что reinterpret_cast может по закону использоваться только для приведения к типу char * или char &?

Я считаю, что строгое алиасирование позволяет выполнять приведение между типами в иерархии наследования, но я думаю, что эти ситуации будут иметь тенденцию использовать dynamic_cast?

Спасибо

3 7

3 ответа:

Есть много различных применений reinterpret_cast. На страницеcppreference перечислены 11 различных случаев.

Я думаю, что вы спрашиваете только о случаях 5 и 6: приведение T * к U * и приведение T к U &.

В этих случаях актерский состав является законным до тех пор, пока нет нарушения выравнивания. Проблема строгого сглаживания возникает только при чтении или записи через результирующее выражение.

Ваше краткое изложение правила строгого сглаживания в вашем первом абзаце является отличным чрезмерное упрощение, в целом существует несколько юридических типов для U. На той же странице cppreference приведен маркированный список случаев; вы можете прочитать точный текст правила в стандартном проекте C++.

Можно также использовать reinterpret_cast для приведения типа указателя к целочисленному типу:

char* ptr = /* ... */
uintptr_t ptrInt = reinterpret_cast<uintptr_t>(ptr);
Конкретное целочисленное значение, которое вы получаете обратно, не переносится между платформами, но это безопасная и четко определенная операция.

Есть и другие полезные применения reinterpret_cast.

Указатель на целочисленный тип

Да, когда-то over хотел бы хранить значение указателя в целочисленном типе.

Единственный способ сделать это с приведениями в стиле C++ - это reinterpret_cast.

Пример:

auto pointerValue = reinterpret_cast<std::uintptr_t>(pointer);

Хранение объектов в блоке необработанной памяти

Иногда вы хотите сохранить данные в стеке, но инициализировать его позже. Использование динамических распределений и указателей не будет использовать стек. std::aligned_storage делает большую работу, как необработанный, выровненный блок памяти.

struct MyStruct {
    int n;
    std::string s;
};

// allocated on automatic storage
std::aligned_storage<sizeof(MyStruct), alignof(MyStruct)>::type storage;

// actually initialize the object
new (&storage) MyStruct;

// using the object
reinterpret_cast<MyStruct*>(&storage)->n = 42;
Я уверен, что есть много других применений, которые я не знаю, но это то, которое я уже использовал.