std::optionalの構築がなぜ std::pairよりも高価 ? 質問する

std::optionalの構築がなぜ std::pairよりも高価 ? 質問する

「オプション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

godbolt.org のライブ例


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 リリース シリーズで修正されました。

おすすめ記事