Листинг С++. Когда будет выполнено static_cast и reinterpret_cast вызовет проблему?
Я понимаю, что a static_cast
- это бросок от одного типа к другому, который (интуитивно) является актом, который при некоторых обстоятельствах может быть успешным и иметь смысл в отсутствие опасного броска. Между тем, reinterpret_cast
- это трансляция, которая представляет собой небезопасное преобразование, которое может переинтерпретировать биты одного значения в виде бит другого значения.
Может кто-нибудь описать сценарий, когда код будет компилироваться, лить и static_cast
не вызовет никаких проблем, но с reinterpret_cast
будет проблема?
Ответы
Ответ 1
Это будет сделано:
#include <iostream>
using namespace std;
struct C{int n;};
struct A{int n;};
struct B : A, C{};
int main()
{
B b;
B* pb = &b;
cout << static_cast<C*>(pb) << "\n";
cout << reinterpret_cast<C*>(pb);
}
Обратите внимание на различия в двух адресах.
Я создал несколько множественных наследований здесь и поместил явный член в базовые классы, чтобы обойти возможную оптимизацию пустых базовых классов до нуля.
См. https://ideone.com/QLvBku
Ответ 2
Простейшим из таких случаев является reinterpret_cast<void*>(NULL)
, который может давать ненулевой указатель.
В отличие от этого, static_cast<void*>(NULL)
является безопасным, поскольку требуется получить нулевой указатель.
Почему? NULL
- целочисленная константа, равная 0. static_cast
требует, чтобы 0 был преобразован в нулевой указатель, но reinterpret_cast
не имеет этого же требования. Если внутреннее представление нулевого указателя не совпадает с внутренним представлением нулевого нуля, результаты будут разными. Этот тип поломки будет, скорее всего, на архитектурах с сегментированной адресацией.
Ответ 3
Одним из таких случаев является множественное наследование - static_cast
выполняет настройку адреса (поэтому адрес указателя базового объекта после трансляции может отличаться от адреса производного объекта, указывать на правильные элементы базового класса).
reinterpret_cast
не выполняет никаких корректировок адресов, поэтому приведение в базовый класс может использовать неправильный адрес (т.е. всегда возвращает адрес производного объекта без изменений).