#include <iostream>
struct Test{
int a;
int b;
};
int main(){
char* buffer = (char*)malloc(sizeof(char)*32); //#a
char* ptr = buffer + 4; //#b
new(ptr) Test; //#c
char* ptr2 = buffer + 4; //#d
Test* tptr = reinterpret_cast<Test*>(ptr2); //#e
tptr->a = 1; // #f
}
Consider the above code, at the point #a, the allocation function malloc allocates a storage region and implicitly create an array object of type char[32], which is mentioned in the following rule:
Some operations are described as implicitly creating objects within a specified region of storage. For each operation that is specified as implicitly creating objects, that operation implicitly creates and starts the lifetime of zero or more objects of implicit-lifetime types ([basic.types]) in its specified region of storage if doing so would result in the program having defined behavior. If no such set of objects would give the program defined behavior, the behavior of the program is undefined. If multiple such sets of objects would give the program defined behavior, it is unspecified which such set of objects is created.
So, the code at #b is well defined, because the pointer buffer can be considered to point to the first element of an array, it satisfies the rule expr.add#4. The code at #c is also well defined, which will construct an object of type Test at the storage to which the ptr points. #d is the same as #b, which is also well defined.
However, consider the code at #e. Now, the pointer ptr2 points to the fourth element of the array(which is created by malloc), the element is an object of type char whose lifetime has ended due to its storage is reused by an object of type Test. The expression reinterpret_cast<Test*>(ptr2) is equivalent to static_cast<Test*>(static_cast<void*>(ptr2)).
A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion.
According to the above rule, an object of type Test is not pointer-interconvertible with an object of type char. So, I think the result is still a pointer to an object of type char, which is the fourth element of the array, merely its lifetime has ended.
So, I wonder Does the code at #f have undefined behaviour due to tptr does not point to an object of type Test? Or as an opposite, Does the pointer tptr indeed point to the object of type Test and the code is well defined? If I miss some other rules, please point it out.