std :: необязательный, реализованный как union vs char [] / align_storage - PullRequest
0 голосов
/ 14 сентября 2018

Читая реализацию 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_;
}

Они выглядят для меня так же, как они функционально идентичны, но есть ли преимущества использования одного над другим?(За исключением очевидного отсутствия размещения новых в последнем, что действительно приятно.)

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Мне они кажутся функционально идентичными, но есть ли преимущества в использовании одного над другим? (За исключением очевидного недостатка размещения нового в последнем, что действительно приятно.)

Это не просто "очень приятно" - это критически важно для действительно важной функциональности, а именно:

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

Есть несколько вещей, которые вы не можете сделать в константном выражении, включая new и reinterpret_cast. Если вы реализовали optional с помощью aligned_storage, вам потребуется использовать new для создания объекта и reinterpret_cast для его возврата, что помешает optional быть constexpr дружественным.

С реализацией union у вас нет этой проблемы, поэтому вы можете использовать optional в constexpr программировании (даже до исправления для тривиального копирования , что Nicol говорит о том, что optional уже требовалось использовать как constexpr).

0 голосов
/ 14 сентября 2018

std::optional не может быть реализован как как выровненное хранилище из-за исправления после C ++ 17.В частности, std::optional<T> должно быть тривиально копируемым, если T тривиально копируемым.union{empty; T t}; удовлетворит это требование

Внутреннее хранение и размещение - new / delete использование не может.Выполнение байтовой копии из объекта TriviallyCopyable в хранилище, в котором еще нет объекта, в модели памяти C ++ недостаточно для фактического создания этого объекта.Напротив, сгенерированная компилятором копия задействованного union поверх TriviallyCopyable типов будет тривиальной и будет работать для создания целевого объекта.

Так что std::optional должен быть реализован таким образом.

...