STLスワップは返されますか?
-
12-10-2019 - |
質問
このような長い質問で申し訳ありませんが、私はできるだけ明確になろうとしています。これはどういうわけか私の以前の質問に従います C ++の文字列. 。冗長メモリの割り当てなしで関数からstd :: stringを返す方法を把握しようとしています。 NRVOに頼らずに. 。私がNRVOに頼りたくない理由は次のとおりです。
- 現在使用しているコンパイラによってサポートされていません
- サポートされていても、デバッグモードで常に有効になるとは限りません
- 場合によっては失敗する可能性があります(例)
C ++ 03互換性のあるソリューションが必要であることに注意してください(C ++ 0x RValue参照はありません。残念ながら...)
これを行う最も簡単な方法は、パスごとに参照し、std :: swap、このようにswapです
void test(std::string& res)
{
std::string s;
//...
res.swap(s);
}
しかし、それは参照で通過するよりも価値で返還する方が自然であり、しばしば便利ですので、私が達成したいのはこれです:
std::string test()
{
std::string s;
//...
return SOMETHING(s);
}
理想的には、それを行うだけです swap
「返品値」では、C ++でこれを行う方法はわかりません。コピーの代わりに移動するauto_ptrが既にあり、実際に使用できます auto_ptr<string>
, 、しかし、私は文字列オブジェクト自体を動的に割り当てることを避けたいと思います。
私の考えは、何らかの形で許可する関数から返されている文字列オブジェクトに「タグ」することです 動く コピーコンストラクターが返されたときに呼び出されたときのデータ。それで、私はこのコードになりました。
struct Str
{
struct Moveable
{
Str & ref;
explicit Moveable(Str & other): ref(other) {}
};
Str() {}
Str(const std::string& other) : data(other) {} // copy
Str(Moveable& other) { data.swap(other.ref.data); } // move
Moveable Move()
{
return Moveable(*this);
}
std::string data;
};
Str test()
{
Str s;
//...
return s.Move(); // no allocation, even without NRVO
}
それで...これはすべて理にかなっていますか、それとも私が欠けているいくつかの深刻な問題がありますか? (たとえば、生涯の問題がないかどうかはわかりません)。たぶん、あなたはすでにそのようなアイデアを図書館(本、記事...)で見たことがありますか?
編集:@RSTEVENSが気づいたように、このコードはMSVC固有であり、非コンスト一時を好まないG ++でコンパイルしません。これ は 問題ですが、この実装がMSVC固有であると仮定しましょう。
解決
Boostの実装は、次のようなライブラリに内部的にMove Semanticsエミュレーションを使用します boost.thread. 。実装を見て、同様のことをしたいかもしれません。
編集: 実際、ライブラリの積極的な開発があります boost.move, 、そのため、すでに使用を開始できます。
他のヒント
G ++でこのコードを確認しましたか?
一時的なオブジェクト(s.move()によって返されたオブジェクトを使用してstr(movable&)を呼び出すため!
これは標準の準拠ではなく、G ++によってサポートされていません。 MSVCによってサポートされています! (MSはこれを機能と呼んでいます...)。
実際に、価値ごとに戻ることがアプリケーションのパフォーマンスの問題であると判断しましたか?これは、最も単純な/最も簡単な方法のように思えます。よりモダンなコンパイラにアップグレードすると、RValue参照を使用できます。
の破壊順序に関する質問に答えることができません s
vs Movable
の参照。コンパイラの場合、さまざまなコンストラクターとデストラクタにコードを入れて、注文が何であるかを確認できます。たとえそれが大丈夫に見えても、読者の混乱を防ぎ、代替コンパイラを破ることを防ぐためだけに、概説した通常のパターンの1つを使用することを検討します。