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)<
For gcc, the unnecessary zeroing with default initialization
std::optional default_init() {
std::optional o;
return o;
}
is bug 86173 and needs to be fixed in the compiler itself. Using the same libstdc++, clang does not perform any memset here.
In your code, you are actually value-initializing the object (through list-initialization). It appears that library implementations of std::optional have 2 main options: either they default the default constructor (write =default;
, one base class takes care of initializing the flag saying that there is no value), like libstdc++, or they define the default constructor, like libc++.
Now in most cases, defaulting the constructor is the right thing to do, it is trivial or constexpr or noexcept when possible, avoids initializing unnecessary things in default initialization, etc. This happens to be an odd case, where the user-defined constructor has an advantage, thanks to a quirk in the language in [decl.init], and none of the usual advantages of defaulting apply (we can specify explicitly constexpr and noexcept). Value-initialization of an object of class type starts by zero-initializing the whole object, before running the constructor if it is non-trivial, unless the default constructor is user-provided (or some other technical cases). This seems like an unfortunate specification, but fixing it (to look at subobjects to decide what to zero-initialize?) at this point in time may be risky.
Starting from gcc-11, libstdc++ switched to the used-defined constructor version, which generates the same code as std::nullopt. In the mean time, pragmatically, using the constructor from std::nullopt where it does not complicate code seems to be a good idea.