現在、Borland C++-Builder 5 および 6 を使用して何年も開発してきたプロジェクトの 1 つを、最新の Embarcadero C++-Builder XE 3 Update 2 に移植しています。XE 3 は、新しい C++11 の一部をサポートしています。前者は非常に古いコンパイラを使用していたため、もちろん私にとっては完全に新しい右辺値参照のようなものです。プロジェクトをコンパイル可能にするために必要な変更はごくわずかでしたが、実行時に、新しい右辺値参照と移動セマンティクスの結果と思われる 1 つの問題に直面しています。
次のような三項演算子でこのフィールドを使用して、1 つのメソッドからのみ読み取られるパスを格納する std::wstring 型のフィールドを持つクラスがあります。
std::wstring retVal = someCondition ? this->classField : Util::doSomething(someArg);
someCondition は std::wstring.empty() への単なる呼び出しであり、Util::doSomething は std::wstring を値として返します。参照も関与もせず、データをコピーしただけです。
XE 3 では、someCondition が初めて true に評価された後、retVal は classField のコンテンツで適切に満たされますが、その後 classField のコンテンツは空になります。デバッガーを使用すると、右辺値を参照する最適化された代入演算子の実行を追跡できます。
#if _HAS_RVALUE_REFERENCES
[...]
_Myt& operator=(_Myt&& _Right)
{ // assign by moving _Right
return (assign(_STD forward<_Myt>(_Right)));
}
_Myt& assign(_Myt&& _Right)
{ // assign by moving _Right
[...]
右辺値参照について読んだことは、私の問題を完全に説明するものであり、classField が右辺値として扱われる理由を説明する 2 つのコメントさえ見つけました。
https://stackoverflow.com/a/8535301/2055163
https://stackoverflow.com/a/6957421
classField の手動コピーを 1 つ追加して、上記の行を修正できます。
std::wstring retVal = someCondition ? std::wstring(this->classField) : Util::doSomething(someArg);
しかし、これはコンパイラの助けを借りずに移植したい各プロジェクトの三項演算子 (左辺値と右辺値が混在する場所) のすべての使用法を確認する必要があるという問題を解決しません。または発生しない場合があります。
私が理解していないのは、三項演算子の使用法に何か問題や悪い習慣があるかどうかです。これらのケースを検出するためのより良い解決策はありますか? 最適化をだますためだけに、一部のオブジェクトを手動でコピーする必要があるのはなぜですか? これは本当に意図した動作であり、ほとんどのコードベースで問題はありませんか? そのような問題にどのように対処しますか?
私は今どのように進行するかについて少し混乱しています。提案や説明があれば本当に感謝しています. ありがとう!
次の2つのケースをテストしました。
最初の例は私の場合と似ていますが、グローバル文字列を格納するためにクラス インスタンスが使用されていないことを期待してください。dummy2 は適切に入力され、ダミーはその内容を保持します。
std::wstring retVal = someCondition ? this->classField : doSomethingResult;
上記の行を変更して、三項演算子を使用する前に Util:... の結果を std::wstring に保存して右辺値を削除すると、すべてが期待どおりに機能します。retVal にはそのコンテンツがあり、this->classField にもそのコンテンツが保持されます。
今の結論は?:-/