I was reading cppreference and in the example for std::aligned_storage is had this example of a vector/array class:
template<class T, std::size_t N>
class static_vector
{
// properly aligned uninitialized storage for N T's
typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
// IF you want to see possible implementation of aligned storage see link.
// It's very simple and small, it's just a buffer
std::size_t m_size = 0;
public:
// Create an object in aligned storage
template<typename ...Args> void emplace_back(Args&&... args)
{
if( m_size >= N ) // possible error handling
throw std::bad_alloc{};
// construct value in memory of aligned storage
// using inplace operator new
new(&data[m_size]) T(std::forward<Args>(args)...);
++m_size;
}
// Access an object in aligned storage
const T& operator[](std::size_t pos) const
{
// note: needs std::launder as of C++17
// WHY
return *reinterpret_cast<const T*>(&data[pos]);
}
// Delete objects from aligned storage
~static_vector()
{
for(std::size_t pos = 0; pos < m_size; ++pos) {
// note: needs std::launder as of C++17
// WHY?
reinterpret_cast<T*>(&data[pos])->~T();
}
}
};
Essentially each bucket/area/address of memory where each element resides is a char buffer. At each element position that exists a placement new is done in that buffer of the T type. So that when returning the position of that buffer that char buffer can be cast to T* because a T was constructed there. Why is std::launder required from C++17 onwards? I have asked a bunch of questions about this and it seems agreed that:
alignas(alignof(float)) char buffer [sizeof(float)];
new (buffer) float;// Construct a float at memory, float's lifetime begins
float* pToFloat = buffer; // This is not a strict aliasing violation
*pToFloat = 7; // Float is live here
This is not a strict aliasing violation apparently, it's completely fine. So therefore why is std::launder required here?