Ну, это цель reinterpret_cast
!Как следует из названия, цель этого приведения - переосмыслить область памяти как значение другого типа.По этой причине, используя reinterpret_cast
, вы всегда можете привести lvalue одного типа к ссылке другого типа.
Это описано в 5.2.10 / 10 спецификации языка.Там также говорится, что reinterpret_cast<T&>(x)
- это то же самое, что и *reinterpret_cast<T*>(&x)
.
Тот факт, что вы используете указатель в этом случае, совершенно и совершенно не важен.Нет, указатель не разыменовывается автоматически (принимая во внимание интерпретацию *reinterpret_cast<T*>(&x)
, можно даже сказать, что верно обратное: адрес этого указателя берется автоматически).Указатель в этом случае служит просто «некоторой переменной, которая занимает некоторую область в памяти».Тип этой переменной не имеет значения вообще.Это может быть double
, указатель, int
или любое другое значение.Переменная просто обрабатывается как область памяти, которую вы переинтерпретируете как другой тип.
Что касается приведения в стиле C - в этом контексте она просто интерпретируется как reinterpret_cast
, поэтомунемедленно применяется к нему.
Во втором примере вы прикрепили ссылку c
к памяти, занятой переменной-указателем pc
.Когда вы сделали c = 'B'
, вы принудительно записали значение 'B'
в эту память, полностью уничтожив исходное значение указателя (перезаписав один байт этого значения).Теперь уничтоженный указатель указывает на непредсказуемое местоположение.Позже вы попытались разыменовать этот уничтоженный указатель.То, что происходит в таком случае, является вопросом чистой удачи.Программа может аварийно завершить работу, поскольку указатель, как правило, не подлежит исправлению.Или вам может повезти и указатель указывает на какое-то непредсказуемое, но действительное местоположение.В этом случае ваша программа что-то выведет.Никто не знает, что он будет выводить, и в этом нет никакого смысла.
Можно переписать вашу вторую программу в эквивалентную программу без ссылок
int main(){
char* pc = new char('A');
char* c = (char *) &pc;
std::cout << *pc << "\n";
*c = 'B';
std::cout << *pc << "\n";
}
С практической точки зрения, нав платформе с прямым порядком байтов ваш код будет перезаписывать младший байт указателя.Такая модификация не заставит указатель указывать слишком далеко от своего первоначального местоположения.Таким образом, код, скорее всего, напечатает что-то, а не падает.На платформе с прямым порядком байтов ваш код будет уничтожать самый значимый байт указателя, поэтому он будет дико выбрасываться, чтобы указывать на совершенно другое место, тем самым повышая вероятность сбоя вашей программы.