I know that the following is explicitly allowed in the standard:
int n = 0;
char *ptr = (char *) &n;
cout << *ptr;
What about this?
alignas(int) char storage[sizeof(int)];
int *ptr = (int *) &storage[0];
*ptr = 0;
cout << *ptr;
Essentially, I'm asking if the aliasing rules allow for a sequence of chars to be accessed through a pointer to another type. I'd like references to the portions of the standard that indicate one way or another if possible.
Some parts of the standard have left me conflicted; (3.10.10) seems to indicate it would be undefined behavior on the assumption that the dynamic type of storage
is not int
. However, the definition of dynamic type is unclear to me, and the existence of std::aligned_storage
would lead me to believe that this is possible.
The strict aliasing rule dictates that pointers are assumed not to alias if they point to fundamentally different types, except for char* and void* which can alias to any other data type.
In both C and C++ the standard specifies which expression types are allowed to alias which types. The compiler and optimizer are allowed to assume we follow the aliasing rules strictly, hence the term strict aliasing rule.
Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.
In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.
The code int *ptr = (int *) &storage[0]; *ptr = 0;
causes undefined behaviour by violating the strict aliasing rule (C++14 [basic.lval]/10)
The objects being accessed have type char
but the glvalue used for the access has type int
.
The "dynamic type of the object" for a char
is still char
. (The dynamic type only differs from the static type in the case of a derived class). C++ does not have any equivalent of C's "effective type" either, which allows typed objects to be "created" by using the assignment operator into malloc'd space.
Regarding correct use of std::aligned_storage
, you're supposed to then use placement-new to create an object in the storage. The use of placement-new is considered to end the lifetime of the char
(or whatever) objects, and create a new object (of dynamic storage duration) of the specified type, re-using the same storage. Then there will be no strict aliasing violation.
You could do the same thing with the char array, e.g.:
alignas(int) char storage[sizeof(int)];
int *ptr = new(storage) int;
*ptr = 0;
cout << *ptr;
Note that no pseudo-destructor call or delete
is required for built-in type int
. You would need to do that if using a class type with non-trivial initialization. Link to further reading
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With