13

在阅读 GCC 的实现时,std::optional我注意到了一些有趣的事情。我知道boost::optional实现如下:

template <typename T>
class optional {
    // ...
private:
    bool has_value_;
    aligned_storage<T, /* ... */> storage_;
}

但是libstdc++libc++(和Abseil)都像这样实现它们的optional类型:

template <typename T>
class optional {
    // ...
private:
    struct empty_byte {};
    union {
        empty_byte empty_;
        T value_;
    };
    bool has_value_;
}

在我看来,它们在功能上是相同的,但是使用其中一个有什么优势吗?(除了后者明显缺乏新的位置,这真的很好。)

4

2 回答 2

17

在我看来,它们在功能上是相同的,但是使用其中一个有什么优势吗?(除了后者中明显缺少新的位置,这真的很好。)

它不仅仅是“非常好”——它对于一个非常重要的功能至关重要,即:

constexpr std::optional<int> o(42);

在常量表达式中有几件事是你不能做的,包括newand reinterpret_cast。如果您使用 实现optionalaligned_storage则需要使用new来创建对象并将reinterpret_cast其取回,这会妨碍optional友好constexpr

有了这个union实现,你就没有这个问题了,所以你可以optionalconstexpr编程中使用(甚至在Nicol所说的对琐碎可复制性的修复之前,已经要求它可以用作)。optionalconstexpr

于 2018-09-14T19:52:44.300 回答
13

std::optional 由于 C++17 后的缺陷修复,无法将其实现为对齐存储。具体来说,std::optional<T>如果是普通可复制的,则需要是普通可T复制的。Aunion{empty; T t};将满足此要求

内部存储和放置new-/delete使用不能。在 C++ 内存模型中,将 TriviallyCopyable 对象的字节复制到尚未包含对象的存储中不足以实际创建该对象。相比之下,编译器生成的unionTriviallyCopyable 类型的副本将是微不足道的,并将用于创建目标对象。

所以std::optional 必须以这种方式实现。

于 2018-09-14T19:41:46.673 回答