15

移動セマンティクスが有効になっている「全体」オブジェクトが、次のように関数から返される場合を考えてみますstd::basic_string<>

std::wstring build_report() const
{
    std::wstring report;
    ...

    return report;
}

次に、返された文字列を移動セマンティクスで使用するかどうかを「最良の」選択にすることが現実的に期待できますか。

const std::wstring report(std::move(build_report()));

または、(N)RVOを使用して実行する必要がある場合

const std::wstring report(build_report());

または、const参照を一時的なものにバインドすることもできます

const std::wstring& report(build_report());

もしあれば、これらのオプションを決定論的に選択するためにどのようなスキームがありますか?

編集1:上記の使用法はstd::wstring、移動セマンティクスが有効なタイプの単なる例であることに注意してください。それはあなたと交換することもできますarbitrary_large_structure。:-)

編集2:次のVS 2010で速度最適化リリースビルドを実行するときに、生成されたアセンブリを確認しました。

std::wstring build_report(const std::wstring& title, const std::wstring& content)
{
    std::wstring report;
    report.append(title);
    report.append(content);

    return report;
}

const std::wstring title1(L"title1");
const std::wstring content1(L"content1");

const std::wstring title2(L"title2");
const std::wstring content2(L"content2");

const std::wstring title3(L"title3");
const std::wstring content3(L"content3");

int _tmain(int argc, _TCHAR* argv[])
{
    const std::wstring  report1(std::move(build_report(title1, content1)));
    const std::wstring  report2(build_report(title2, content2));
    const std::wstring& report3(build_report(title3, content3));

    ...

    return 0;
}

2つの最も興味深い結果:

  • 明示的にmoveコンストラクターの使用を要求std::moveすると、命令数が3倍になります。report1
  • 以下の回答でreport2JamesMcNellisが指摘しているように、report3実際には、明示的に呼び出すよりも3分の1の命令で同一のアセンブリを生成しstd::moveます。
4

3 に答える 3

13

std::move(build_report())完全に不要です: build_report()はすでに右辺値式(オブジェクトを値で返す関数の呼び出しです)であるため、std::wstringmoveコンストラクターが存在する場合はそれが使用されます(存在する場合)。

さらに、ローカル変数を返す場合、moveコンストラクターを持つタイプの場合は移動されるため、コピーは作成されません。

reportオブジェクトとして宣言することとconst-referenceとして宣言することの間に機能的な違いがあってはなりません。どちらの場合も、最終的にオブジェクト(参照をバインドできる名前付きreportオブジェクトまたは名前なしオブジェクトのいずれか)になります。report

于 2011-06-30T08:04:29.340 に答える
4

これが標準化されているかどうかはわかりませんが(Nicolが言うように、すべての最適化はコンパイラー次第です)、 STLがこれについて話しているのを聞きました。 (少なくともMSVCでは)RVOは何よりも先に発生します。したがって、RVOを適用する機会があれば、それはあなたの側で何のアクションもなしに起こります。次に、一時を返す場合、戻り値は暗黙的に右辺値として扱われるため、書き込む必要はありません(これstd::move実際には標準に含まれていると思います)。

結果は次のとおりです。コンパイラを二度と推測しないでください。最も自然に見えるコードを書くだけで、可能な限り最高の結果が得られます。

于 2011-06-30T10:09:16.083 に答える
3

もしあれば、これらのオプションを決定論的に選択するためにどのようなスキームがありますか?

存在しません、そして決して存在しません。

コンパイラは、いかなる種類の最適化も行う必要はありません。確実にできることは、コードをコンパイルして、もう一方の端から何が出るかを確認することだけです。

最終的に得られるもののほとんどは、一般的なヒューリスティックであり、コミュニティのコンセンサスであり、「ほとんどのコンパイラでは、Xが最も高速に動作するようです」と言われます。しかし、それはそれについてです。そして、コンパイラーがC ++ 0xに習熟し、実装が成熟するにつれて、これには何年もかかります。

于 2011-06-30T08:11:43.073 に答える