考虑这两种可以表示“可选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};
}
...both 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
需要三条mov
指令,而 get_my_optional()
只需要一条 QoI指令这是一个std::optional
问题,还是std::optional
的规范中有什么东西阻止了这种优化?
还请注意,无论如何,函数的用户可能都会被完全优化:
volatile int a = 0;
volatile int b = 0;
int main()
{
a = get_std_optional_int().value();
b = get_my_optional().first;
}
...results in:
main:
mov DWORD PTR a[rip], 42
xor eax, eax
mov DWORD PTR b[rip], 42
ret
发布于 2017-10-03 22:08:41
libstdc++显然没有实现P0602 "variant and optional should propagate copy/move triviality"。您可以使用以下命令验证这一点:
static_assert(std::is_trivially_copyable_v<std::optional<int>>);
which fails for libstdc++, and passes for libc++ and the MSVC standard library (它确实需要一个恰当的名称,这样我们就不必称它为“C++标准库的MSVC实现”或“MSVC STL")。
当然,MSVC仍然不会在寄存器中传递optional<int>
,因为MSVC。
编辑:此问题已在GCC 8发布系列中修复。
发布于 2017-10-03 20:22:40
在Calling conventions for different C++ compilers and operating systems by Agner Fog中,它说复制构造函数或析构函数阻止在寄存器中返回结构。这就解释了为什么寄存器中不返回optional
。
必须有其他东西阻止编译器进行存储合并(将比一个单词更窄的立即值的连续存储合并到更少的更宽的存储中,以减少指令的数量)。更新: gcc bug 82434 - -fstore-merging does not work reliably.
https://stackoverflow.com/questions/46544019
复制相似问题