4

我正在阅读 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 呢?

4

1 回答 1

1
    // note: needs std::launder as of C++17
    return *reinterpret_cast<const T*>(&data[pos]);

为什么从 C++17 开始需要 std::launder?

您可以从中取消引用指针的条件reinterpret_cast是最小的。这不是其中的一个。您正在将指向一种类型的指针转​​换为指向完全不相关类型的指针,并通读它。见这里

std::launder允许您派生一个有效的指针。它存在的全部理由就是给你这个。

在 C++17 之前,您必须保存从位置 new 返回的指针,因为这是唯一有效的指针T,并且在std::launder您无法从缓冲区中创建一个之前。

我已经问了很多关于这个的问题,并且似乎同意......这显然不是一个严格的混叠违规,它完全没问题。那么为什么这里需要 std::launder 呢?

出于同样的原因,这不好。也没有同意这很好。在此处查看@eerorika 对您的问题的回答。

于 2021-08-29T03:43:47.643 回答