Нераспределенный доступ к памяти: это определенное поведение или нет?
Рассмотрим следующий код:
#include <iostream>
int main()
{
char* c = new char('a');
char ac[4] = {'a', 'b', 'c', 'd'};
unsigned long long int* u = reinterpret_cast<unsigned long long int*>(c);
unsigned long long int* uc = reinterpret_cast<unsigned long long int*>(&ac[3]);
*u = 42;
*uc = 42;
std::cout<<*u<<" "<<*uc<<std::endl;
}
Это считается допустимым кодом, или это утечка памяти / неопределенное поведение? Я спрашиваю, потому что через:
*u = 42;
*uc = 42;
мы получаем доступ к байтам, которые не должны быть доступны для программы (я полагаю).
1 ответ
*u = 42;
вызывает неопределенное поведение, нарушая строгое правило алиасинга. *u
является lvalue типа unsigned long long
и строгое правило псевдонимов говорит, что это может использоваться только для доступа к объектам (которые уже существуют) и имеют тип long long
или же unsigned long long
, Однако ваш код использует его для доступа к массиву char
,
В C++ нет специального правила для выровненного доступа (в отличие от C). Это связано с тем, что в C++ невозможно написать код, который выполнял бы невыровненный доступ, не вызывая неопределенного поведения, из-за одной из следующих вещей:
- нарушая строгое правило алиасинга.
- доступ к памяти, где нет объекта.
- предоставление невыровненного адреса для размещения новых.