std :: необязательный, реализованный как union против char [] / align_storage

Читая через реализацию GCC std::optional Я заметил кое-что интересное. я знаю boost::optional реализован следующим образом:

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

Но тогда оба libstdc ++ а также Libc ++ (а также спускаться с крутизны на веревке) реализовать их optional типа как это:

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

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

8

Решение

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

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

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

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

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

11

Другие решения

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

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

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

9

По вопросам рекламы [email protected]