Consider the following example in C++14:
alignas(T) unsigned char data[sizeof(T)];
new (data) T();
T* p = reinterpret_cast<T*>(data);
p->something(); // UB?
Is this code legal, or are the Strict Aliasing rules being violated, since unsigned char*
may not be aliased by T*
? If it's legal, what parts of the Standard explicitly say so?
cppreference has a similar example which claims std::launder
must be used in C++17. What does this mean for C++14, where we don't have std::launder
?
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
// Note: std::launder is needed after the change of object model in P0137R1
return *std::launder(reinterpret_cast<const T*>(&data[pos]));
}
Thanks everyone for your replies! I will try to answer the question combining the knowledge I've gotten from the responses.
There is no Strict Aliasing violation
As per basic.life#2:
The lifetime of an array object starts as soon as storage with proper size and alignment is obtained, and its lifetime ends when the storage which the array occupies is reused or released
Therefore, after the placement new
call, the char
array no longer contains objects of type char
. It contains a newly created object of type T
.
Later, we access the object of type T
via a T*
, which is a valid alias. Therefore, Strict Aliasing rules are not violated here.
Lifetime
The real problem is lifetime. When we reinterpret_cast<T*>(data)
, we are using a pointer (data
) that points to expired data, since it has been replaced by the new object. There is no guarantee that the data
pointer is "updated" to point to the newly-created object.
T
via the pointer returned by placement new
.data
, as long as we launder it via std::launder
. This allows not having to store the pointer returned by placement new
.