Подтвердить что ты не робот

Листинг С++. Когда будет выполнено static_cast и reinterpret_cast вызовет проблему?

Я понимаю, что a static_cast - это бросок от одного типа к другому, который (интуитивно) является актом, который при некоторых обстоятельствах может быть успешным и иметь смысл в отсутствие опасного броска. Между тем, reinterpret_cast - это трансляция, которая представляет собой небезопасное преобразование, которое может переинтерпретировать биты одного значения в виде бит другого значения.

Может кто-нибудь описать сценарий, когда код будет компилироваться, лить и static_cast не вызовет никаких проблем, но с reinterpret_cast будет проблема?

4b9b3361

Ответ 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 не выполняет никаких корректировок адресов, поэтому приведение в базовый класс может использовать неправильный адрес (т.е. всегда возвращает адрес производного объекта без изменений).