Dre*_*ann 28 c++ optional c++17
我认为初始化std::optionalwith与std::nullopt默认构造相同。
它们在cppreference中的描述与形式(1)相同。
但是,Clang和GCC似乎都不同地对待这些玩具示例函数。
#include <optional>
struct Data {
char large_data[0x10000];
};
std::optional<Data> nullopt_init() {
return std::nullopt;
}
std::optional<Data> default_init() {
return {};
}
Run Code Online (Sandbox Code Playgroud)
编译器资源管理器似乎暗示使用std::nullopt会简单地设置“ contains”标志,
nullopt_init():
mov BYTE PTR [rdi+65536], 0
mov rax, rdi
ret
Run Code Online (Sandbox Code Playgroud)
虽然默认构造将值初始化整个类。这在功能上是等效的,但几乎总是比较昂贵。
default_init():
sub rsp, 8
mov edx, 65537
xor esi, esi
call memset
add rsp, 8
ret
Run Code Online (Sandbox Code Playgroud)
这是故意行为吗?什么时候应该优先使用另一种形式?
T.C*_*.C. 17
在这种情况下,{}调用值初始化。如果optional的默认构造函数不是由用户提供的(其中“未由用户提供”的意思是大致“在类定义中隐式声明或显式默认”),则将导致整个对象的零初始化。
是否这样做取决于特定std::optional实现的实现细节。看起来libstdc ++ optional的默认构造函数不是用户提供的,而libc ++的是。
对于gcc,使用默认初始化进行不必要的归零
std::optional<Data> default_init() {
std::optional<Data> o;
return o;
}
Run Code Online (Sandbox Code Playgroud)
是bug 86173,需要在编译器本身中进行修复。使用相同的libstdc ++,clang在此处不执行任何memset。
现在,在您的代码中,您实际上是在对对象进行值初始化(通过列表初始化)。看来,的库实现std::optional有2个主要选项:或者使默认构造函数变得无关紧要(libstdc ++),这具有一些优点,但会强制整个缓冲区初始化为零。或者他们提供了一个默认的构造函数(libc ++),该构造函数仅初始化需要的内容(例如来自的构造函数std::nullopt),但是却失去了琐碎的功能。可悲的是,似乎无法兼具两者的优势。我想我更喜欢第二版。同时,务实地使用std::nullopt不使代码复杂化的构造函数似乎是一个好主意。