1. ホーム
  2. c++

[解決済み] C++11 rvalues と移動セマンティクスの混乱(return 文)

2022-03-21 13:22:42

質問

C++11のrvalue参照と移動のセマンティクスを理解しようとしています。

これらの例のうち、ベクターコピーをしないのはどちらでしょうか?

最初の例

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> &&rval_ref = return_vector();

2番目の例

std::vector<int>&& return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

第3の例

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

解決方法は?

最初の例

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> &&rval_ref = return_vector();

最初の例では、一時的なものを返しています。 rval_ref . このテンポラリは rval_ref を定義し、それを値でキャッチしたかのように使用することができます。 これは、次のように非常によく似ています。

const std::vector<int>& rval_ref = return_vector();

ただし、私のリライトでは、明らかに rval_ref を非恒久的に使用することができます。

2番目の例

std::vector<int>&& return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

2つ目の例では、ランタイムエラーを発生させていますね。 rval_ref への参照を保持しています。 tmp を関数内で使用します。 運が良ければ、このコードはすぐにクラッシュするでしょう。

3つ目の例

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

3つ目の例は、1つ目の例とほぼ同じです。 その std::movetmp は不要であり、戻り値の最適化を阻害するため、実際にはパフォーマンスの低下を招く可能性があります。

やっていることをコード化するのに最適なのは

ベストプラクティス

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> rval_ref = return_vector();

つまり、C++03のときと同じように。 tmp はreturn文の中で暗黙のうちにrvalueとして扱われます。 これは、return-value-optimization(コピー、移動なし)で返されるか、コンパイラがRVOを実行できないと判断した場合は は、vector の移動コンストラクタを使用して返します。 . RVO が実行されず、戻り値の型に移動コンストラクタがない場合のみ、戻り値にコピーコンストラクタが使用されます。