2011-12-18 2 views
5

В соответствии со строгими правилами наложения спектров:символьные * преобразования и правила наложения спектров

struct B { virtual ~B() {} }; 
struct D : public B { }; 

D d; 
char *c = reinterpret_cast<char*>(&d); 

char* к любому объекту другого типа является действительным. Но теперь вопрос в том, укажет ли тот же адрес & d? Какова гарантия, предоставленная C++ Standard, что он вернет тот же адрес?

+9

Я думаю, что ваш деструктор неверно назван –

+4

Я не знаю ответа. Но когда это знание ** будет полезно на практике? –

+0

Хороший вопрос. Некоторые приведения могут фактически изменить адрес (например, когда задействовано множественное наследование).Интересно, так ли это. – Kos

ответ

6

c и &d действительно имеют такое же значение, и если вы переосмысливать отливка c назад к D* вы получите правильный указатель, что вы можете разыменования. Кроме того, вы можете обрабатывать c как (указатель на первый элемент) непрозрачного массива char[sizeof(D)] - это действительно основная цель указателей каста для указателей на символы: разрешить (де) сериализацию (например, ofile.write(c, sizeof(D));), хотя обычно вы должны только сделайте это для примитивных типов (и их массивов), поскольку бинарная компоновка составных типов обычно не указывается переносимым образом.

Как @Oli справедливо указывает и хотел бы, чтобы я укрепился, вы никогда не должны сериализовать сложные типы в целом. Результат почти никогда не будет десериализуем, поскольку реализация полиморфных классов и дополнений между полями данных не указана и недоступна для вас.

Обратите внимание, что reinterpret_cast<char*>(static_cast<B*>(&d)) может рассматриваться как непрозрачный массив char[sizeof(B)] по аналогичным соображениям.

+0

Я думаю, что, возможно, вам следует пояснить, что сериализация/десериализация не-POD-классов, подобных этой (то есть с vptrs), является очень плохой идеей. –

+0

@OliCharlesworth: Hm, * objects * не имеют скрытых «vptrs» ... это все только в реализации класса. Объекты должны по-прежнему иметь довольно «нормальный» макет, по крайней мере, до тех пор, пока вы не получите виртуальное наследование ... обычные проблемы с заполнением - это гораздо более непосредственная причина не сериализовать типы классов в «наивном» способе (хотя опять же может быть ситуации, где это нормально, например кластеры HPC идентичных машин с использованием сетевых подключений с памятью ...). Покупатель берегитесь :-) –

+0

Что? Существование виртуальных функций означает, что экземпляры класса должны иметь vptr (ну, в любой типичной реализации). –

2

Раздел 5.2.10, пункт 7 Стандарта ++ 2003 C говорит:

Указатель на объект может быть явно преобразован в указатель на объект другого типа. Кроме того, что преобразование значения типа «указатель на T1» на тип «указатель на T2» (где T1 и T2 - это типы объектов , а требования к выравниванию T2 не являются , более строгими, чем требования T1) и его исходный тип дает исходное значение указателя , результатом такого преобразования указателя является неуказанный.

Если по «одному адресу» вы имеете в виду «исходное значение указателя», тогда в этой записи говорится «да».

0

Цель ясна (а не то, что должно обсуждаться):

reinterpret_cast никогда не изменяет значение адреса, если целевой тип не может представлять все значения адресов (например, небольшого целого типа, по типу указателя с внутренним выравниванием: f.ex. не может смешиваться указатель, который может представлять только четные адреса, или указатели на объект и указатели на функции ...).

Формулировка стандарта не позволяет зафиксировать это, но это не означает, что здесь существует реальная практическая проблема.

char *c = reinterpret_cast<char*>(&d); 

c будет указывать на первый байт d, всегда.

Смежные вопросы