I thought that initializing a std::optional
with std::nullopt
would be the same as default construction.
They are described as equivalent at cppreference, as form (1)
However, both Clang and GCC seem to treat these toy example functions differently.
#include <optional>
struct Data { char large_data[0x10000]; };
std::optional<Data> nullopt_init()
{
return std::nullopt;
}
std::optional<Data> default_init()
{
return {};
}
Compiler Explorer seems to imply that using std::nullopt
will simply set the one byte "has_value
" flag,
nullopt_init():
mov BYTE PTR [rdi+65536], 0
mov rax, rdi
ret
While default construction will value-initialize every byte of the class. This is functionally equivalent, but almost always costlier.
default_init():
sub rsp, 8
mov edx, 65537
xor esi, esi
call memset
add rsp, 8
ret
Is this intentional behavior? When should one form be preferred over the other?
Update: GCC (since v11.1) and Clang (since v12.0.1) now treat both forms efficiently.
In this case, {}
invokes value-initialization. If optional
's default constructor is not user-provided (where "not user-provided" means roughly "is implicitly declared or explicitly defaulted within the class definition"), that incurs zero-initialization of the entire object.
Whether it does so depends on the implementation details of that particular std::optional
implementation. It looks like libstdc++'s optional
's default constructor is not user-provided, but libc++'s is.