c++ - 为什么这里需要 std::launder ?

标签 c++ undefined-behavior strict-aliasing stdlaunder

我正在阅读 cppreference 并在 std::aligned_storage 的示例中有一个 vector/数组类的例子:

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 呢?

最佳答案

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

Why is std::launder required from C++17 onwards?


您可以从 reinterpret_cast 取消引用指针的条件是最小的。这不是其中的一个。您正在将指向一种类型的指针转​​换为指向完全不相关类型的指针,并通读它。见 here .std::launder允许您派生有效的指针。存在的全部理由就是给你这个。
在 C++17 之前,您必须保存从 Placement new 返回的指针,因为它是唯一有效的指向 T 的指针。就在眼前,之前std::launder你不能从缓冲区制作一个。

I have asked a bunch of questions about this and it seems agreed that... This is not a strict aliasing violation apparently, it's completely fine. So therefore why is std::launder required here?


出于同样的原因,这不好。也没有人同意这很好。请参阅@eerorika 在 your question here 上的回答.

关于c++ - 为什么这里需要 std::launder ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68869404/

相关文章:

c++ - 一个好的重新分区算法

c++ - 是不是捕获了异常未定义的行为?

c++ - union 的使用定义明确了吗?

c++ - 在没有 std::launder 的情况下将 std::aligned_storage* 重新解释为 T* 是否违反严格别名规则?

c - 为什么严格的别名规则不适用于 int* 和 unsigned*?

c++ - 带有 uint8_t 的 reinterpret_cast 是否违反了严格别名规则?

c++ - 是否可以在已分配的内存上初始化 std::vector ?

c++ - 在 OpenCV 的 FlannBasedMatcher 中,训练究竟发生在什么阶段?

c++ - 如何测量 sqlite3 查询所用的时间?

c++ - 表达式 (a=b) = k UB?