我正在阅读 cppreference 并且在std::aligned_storage的示例中有一个向量/数组类的示例:
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();
}
}
};
本质上,每个元素所在的每个存储桶/区域/内存地址都是一个字符缓冲区。在存在的每个元素位置,都会在 T 类型的缓冲区中完成新的放置。因此,当返回该缓冲区的位置时,可以将 char 缓冲区转换为 T*,因为在那里构造了一个 T。为什么从 C++17 开始需要 std::launder?我已经问了很多关于这个的问题,似乎同意:
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
这显然不是严格的混叠违规,完全没问题。那么为什么这里需要 std::launder 呢?