考虑一下以下两种方法,它们都可以表示一个“可选的 int
”:
using std_optional_int = std::optional<int>;
using my_optional_int = std::pair<int, bool>;
考虑这两个函数...
auto get_std_optional_int() -> std_optional_int
{
return {42};
}
auto get_my_optional() -> my_optional_int
{
return {42, true};
}
...g++ trunk和clang++ trunk(使用-std=c++17 -Ofast -fno-exceptions -fno-rtti
)都会生成以下汇编代码:
get_std_optional_int():
mov rax, rdi
mov DWORD PTR [rdi], 42
mov BYTE PTR [rdi+4], 1
ret
get_my_optional():
movabs rax, 4294967338 // == 0x 0000 0001 0000 002a
ret
为什么get_std_optional_int()
需要三个mov
指令,而get_my_optional()
只需要一个movabs
?这是一个QoI问题,还是std::optional
的规范中有阻止此优化的内容?
此外,请注意函数的用户可能会被完全优化掉:
volatile int a = 0;
volatile int b = 0;
int main()
{
a = get_std_optional_int().value();
b = get_my_optional().first;
}
...得到的结果是:
main:
mov DWORD PTR a[rip], 42
xor eax, eax
mov DWORD PTR b[rip], 42
ret
boost::optional
存在相同的问题,在任何版本的 GCC 上都可以复现,不需要使用花哨的 C++17 来演示:https://godbolt.org/g/MV14mr - John Zwinckfolly::Optional
没有必要的魔法来使其特殊成员函数有条件地平凡化。它还通过在内联函数中使用内部链接的 "None" 违反了ODR,并且每个单独的constexpr
或者FOLLY_CPP14_CONSTEXPR
函数都是不合规范的 NDR: 你不能用aligned_storage
实现optional
的constexpr
API。虽然可以使用co_await
,但最好从range-v3中窃取optional
实现,然后添加其余的API。 - Casey