「オプションint
」を表すことができる次の 2 つのアプローチを検討してください。
using std_optional_int = std::optional<int>;
using my_optional_int = std::pair<int, bool>;
これら 2 つの関数を考えると...
auto get_std_optional_int() -> std_optional_int
{
return {42};
}
auto get_my_optional() -> my_optional_int
{
return {42, true};
}
...両方g++ トランクそしてclang++ トランク (と-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()
では3 つの命令が必要なmov
のに、 ではget_my_optional()
1 つの命令しか必要ないのはなぜですか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
ベストアンサー1
libstdc++は明らかに実装していないP0602 「バリアントとオプションはコピー/移動の単純性を伝播する必要がある」これを検証するには、次の操作を実行します。
static_assert(std::is_trivially_copyable_v<std::optional<int>>);
libstdc++では失敗し、libc++とMSVC標準ライブラリでは成功します。(適切な名前が必要なので、「C++ 標準ライブラリの MSVC 実装」や「MSVC STL」と呼ぶ必要はありません)。
もちろんMSVCまだoptional<int>
MS ABI のため、レジスタに渡されません。
編集: この問題は GCC 8 リリース シリーズで修正されました。