std :: optional-用{}或std :: nullopt构造为空?

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 ++的是。

  • 这并不妨碍实现“=default;”。我认为它在合格的程序中是不可观察到的,所以就好像适用。 (2认同)
  • 我可以推断出“什么时候应该首选一种形式而不是另一种形式?”的答案,但您是否愿意提供一种形式?似乎有[这里的几个帖子](/sf/ask/2802751241/)暗示等价,但事实似乎并非如此。 (2认同)

Mar*_*sse 6

对于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不使代码复杂化的构造函数似乎是一个好主意。

  • “可选”的默认构造函数不能是微不足道的;您需要初始化“有值”标志。 (2认同)