Читая через реализацию 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_;
}
Они выглядят для меня так же, как они функционально идентичны, но есть ли преимущества использования одного над другим? (За исключением очевидного отсутствия размещения нового в последнем, что действительно приятно.)
Они выглядят для меня так же, как они функционально идентичны, но есть ли преимущества использования одного над другим? (За исключением очевидного недостатка размещения нового в последнем, что действительно приятно.)
Это не просто «очень приятно» — это важно для действительно важной функциональности, а именно:
constexpr std::optional<int> o(42);
Есть несколько вещей, которые вы не могу делать в постоянном выражении, и те включают в себя new
а также reinterpret_cast
, Если вы реализовали optional
с aligned_storage
, вам нужно будет использовать new
создать объект и reinterpret_cast
чтобы вернуть его обратно, что помешало бы optional
из того constexpr
дружелюбный.
С union
реализации, у вас нет этой проблемы, поэтому вы можете использовать optional
в constexpr
программирование (даже до исправить для тривиального копирования тот Nicol говорит о том, optional
уже был необходим для использования в качестве constexpr
).
std::optional
не могу быть реализовано как выровненное хранилище из-за исправления дефекта после C ++ 17. В частности, std::optional<T>
должно быть легко копируемым, если T
тривиально копируемый. union{empty; T t};
удовлетворит это требование
Внутреннее хранение и размещениеnew
/delete
использование не может. Создание байтовой копии из объекта TriviallyCopyable в хранилище, в котором еще нет объекта, в модели памяти C ++ недостаточно для фактического создания этого объекта. Напротив, сгенерированная компилятором копия занятого union
над TriviallyCopyable типов будет тривиальным и будет работать для создания целевого объекта.
Так std::optional
должен быть реализован таким образом.