I thought that initializing a std::optional with std::nullopt would be the same as default construction.
They are described as the same at cppreference, as form (1)<
The standard doesn't say anything about the implementation of those two constructors. According to [optional.ctor]:
constexpr optional() noexcept;
constexpr optional(nullopt_t) noexcept;
*this does not contain a value.T these constructors shall be constexpr constructors (9.1.5).It just specifies the signature of those two constructors and their "Ensures" (aka effects): after any of those constructions the optional doesn't contain any value. No other guarantees are given.
Whether the first constructor is user-defined is implementation-defined (i.e depends on the compiler).
If the first constructor is user-defined, it can of course be implemented as setting the contains flag. But a non-user-defined constructor is also compliant with the standard (as implemented by gcc), because this also zero-initialize the flag to false. Although it does result in costy zero-initialization, it doesn't violate the "Ensures" specified by the standard.
As it comes to real-life usage, well, it is nice that you have dug into the implementations so as to write optimal code.
Just as a side-note, probably the standard should specify the complexity of those two constructors (i.e O(1) or O(sizeof(T)))