問題タブ [rvalue-reference]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - C++0x右辺値参照-左辺値-右辺値バインディング
これは、 C++0x右辺値参照と一時的なものに対する後続の質問 です。
前の質問で、このコードがどのように機能するかを尋ねました。
暗黙の一時的なもののために移動オーバーロードを呼び出す必要があるようです。これはGCCでは発生しますが、MSVC(またはMSVCのIntellisenseで使用されるEDGフロントエンド)では発生しません。
このコードはどうですか?
以前の質問への回答に基づくと、機能g1
は合法であるようです(GCC 4.3-4.5では受け入れられますが、MSVCでは受け入れられません)。g2
ただし、 13.3.3.1.4 / 3節では、左辺値が右辺値のref引数にバインドできないため、GCCとMSVCはどちらも拒否します。私はこの背後にある理論的根拠を理解しています-それはN2831「右辺値参照による安全性の問題の修正」で説明されています。また、GCCの元のパッチは著者の1人(Doug Gregor)によって書かれたため、GCCはおそらくその論文の著者が意図したとおりにこの条項を実装していると思います。
しかし、これは非常に直感的ではありません。私にとって、(a)aconst string &
は概念的にastring &&
よりもaconst char *
に近く、(b)コンパイラは、次のg2
ように記述されているかのように、に一時的な文字列を作成できます。
実際、コピーコンストラクターは暗黙の変換演算子と見なされる場合があります。構文的には、これはコピーコンストラクターの形式で提案され、標準では13.3.3.1.2/4節で具体的に言及されています。ここでは、派生ベース変換のコピーコンストラクターに他のユーザー定義よりも高い変換ランクが与えられます。変換:
クラスタイプの式の同じクラスタイプへの変換には完全一致ランクが与えられ、クラスタイプの式のそのタイプの基本クラスへの変換には、コピー/移動にもかかわらず、変換ランクが与えられます。これらの場合、コンストラクター(つまり、ユーザー定義の変換関数)が呼び出されます。
void h(Base)
(これは、派生クラスを、基本クラスを値で受け取るのような関数に渡すときに使用されると思います。)
動機
これを尋ねる私の動機は、新しいc ++ 0x右辺値参照演算子のオーバーロードを追加するときに冗長コードを減らす方法(「新しいc ++ 0x右辺値参照演算子のオーバーロードを追加するときに冗長コードを減らす方法」)で尋ねられた質問のようなものです。
移動可能な可能性のある多数の引数を受け入れる関数があり、可能な場合はそれらを移動し(たとえば、ファクトリ関数/コンストラクターObject create_object(string, vector<string>, string)
など)、必要に応じて各引数を移動またはコピーする場合は、すぐに記述を開始します。たくさんのコード。
引数の型が移動可能である場合は、上記のように、値で引数を受け入れる1つのバージョンを記述できます。ただし、引数がC ++ 03の(レガシー)移動不可であるが交換可能なクラスであり、それらを変更できない場合は、右辺値参照のオーバーロードを作成する方が効率的です。
したがって、左辺値が暗黙的なコピーを介して右辺値にバインドされた場合、次のようなオーバーロードを1つだけ記述することができcreate_object(legacy_string &&, legacy_vector<legacy_string> &&, legacy_string &&)
、右辺値と左辺値の参照オーバーロードのすべての組み合わせを提供するように機能します-左辺値であった実際の引数はコピーされてからバインドされます引数には、右辺値である実際の引数が直接バインドされます。
明確化/編集:これは、C ++ 0x std::stringやstd::vectorのような可動型の値による引数の受け入れと実質的に同じであることに気付きました(moveコンストラクターが概念的に呼び出される回数を保存します)。ただし、コピー可能であるが移動不可能なタイプの場合は同じではありません。これには、明示的に定義されたコピーコンストラクターを持つすべてのC++03クラスが含まれます。この例を考えてみましょう。
g
を呼び出すf
と、x
とがコピーされy
ます-コンパイラがそれらを移動する方法がわかりません。f
代わりに引数を取ると宣言された場合、呼び出し元が引数に対してlegacy_string &&
明示的に呼び出したコピーを回避できstd::move
ます。これらがどのように同等であるかわかりません。
質問
私の質問は次のとおりです。
- これは標準の有効な解釈ですか?とにかく、それは従来のものでも意図されたものでもないようです。
- 直感的に理解できますか?
- 私が見ていないというこの考えに問題はありますか?それが正確に予期されていないときにコピーが静かに作成される可能性があるようですが、それはとにかくC ++ 03の場所の現状です。また、それはいくつかを作りますオーバーロードは現在実行可能ではないときに実行可能ですが、実際には問題になるとは思いません。
- これは、GCCの実験的なパッチなどを作成する価値があるほど重要な改善ですか?
c++ - 可変引数関数のすべての引数で std::forward を呼び出すにはどうすればよいですか?
私はちょうどジェネリック オブジェクト ファクトリを作成し、boost プリプロセッサ メタ ライブラリを使用して可変個引数テンプレートを作成していました (2010 を使用しており、それらをサポートしていません)。私の関数は rval 参照を使用std::forward
して完全な転送を行い、考えさせられました... C++ 0X が出てきて標準コンパイラがあれば、実際の可変個引数テンプレートでこれを行うでしょう。しかし、どうすればstd::forward
引数を要求できますか?
私が考えることができる唯一の方法は、 ...params の手動アンパックを必要とすることであり、私もまだそこにいません。動作するより高速な構文はありますか?
c++ - 参照の過負荷と、唯一の値渡し+ std :: move?
C ++ 0xの右辺値に関する主なアドバイスは、コンパイラーがデフォルトで実装するまで、moveコンストラクターとmove演算子をクラスに追加することです。
ただし、VC10を使用する場合、待機は失われる戦略です。自動生成は、VC10 SP1、または最悪の場合はVC11まではおそらくここにないからです。おそらく、これを待つ時間は数年で測定されます。
ここに私の問題があります。この重複したコードをすべて書くのは楽しいことではありません。そして、見るのは不快です。しかし、これは、遅いと見なされるクラスにとって、好評の負担です。数千とまではいかなくても、数百の小さなクラスではそうではありません。
::ため息::C++ 0xを使用すると、コードの記述量を増やすことはできません。
そして、私は考えました。多くの人が共有していると思います。
すべてを値で渡すだけではどうでしょうか。std :: move + copy elisionはこれをほぼ最適にしませんか?
例1-典型的なPre-0xコンストラクター
短所:右辺値の無駄なコピー。
例2-推奨されるC++0x?
長所:おそらく最速です。
短所:たくさんのコード!
例3-値渡し+std:: move
長所:追加のコードはありません。
短所:ケース1と2での無駄な移動SomeClass
。移動コンストラクターがないと、パフォーマンスが大幅に低下します。
どう思いますか?これは正しいです?コード削減のメリットと比較した場合、発生した移動は一般的に許容できる損失ですか?
c++ - 右辺値メソッドで*thisから移動しますか?
C ++ 11では、メソッドが呼び出されるオブジェクトを表す式が左辺値であるか右辺値であるかによって、メソッドをオーバーロードできます。*this
右辺値を介して呼び出されたメソッドから戻る場合、明示的にmove
fromする必要があり*this
ますか?
残念ながら、g ++はまだこの機能をサポートしていないため、コンパイラでこれを簡単にテストすることはできません:(
c++ - 最小で完璧な転送
minアルゴリズムは通常、次のように表されます。
ただし、これはフォームの構成を許可しませんmin(a, b) = 0
。追加のオーバーロードでそれを達成できます:
私がやりたいのは、完全な転送を介してこれら2つのオーバーロードを統合することです。
ただし、g ++ 4.5.0はmin(2, 4)
、一時への参照を返すという警告を出します。私は何か間違ったことをしましたか?
わかりました。わかりました。問題は条件演算子にあります。私の最初の解決策ではmin(2, 4)
、条件演算子を呼び出すとxvalueが表示されるため、転送されたものから移動しx
て一時オブジェクトを生成します。もちろん、それを参照して返すのは危険です!式全体を個別に転送するのではなく転送するx
とy
、コンパイラはもう文句を言いません。
さて、私は算術型の参照を取り除きました:)
c++ - 右辺値参照は暗黙の変換を許可しますか?
次のコードは合法ですか?
g ++ 4.5.0は、このコードを問題なくコンパイルします。
c++ - ひねりを加えた一時的な住所の取得
関数があり、引数に(カプセル化された)address_of
を返します。は左辺値と右辺値の両方で動作する必要があるため、 には 2 つのバージョンがあります。1 つは参照を受け入れ、もう 1 つは右辺値参照を受け入れます。テンポラリーのアドレスを取得することは悪いことなので、 の右辺値バージョンは、が実際に何かを所有するためにムーブ コンストラクトを実行する必要があります。実装は簡単です:Pointer
shared_ptr
address_of
address_of
address_of
Pointer
そして、期待どおりに一時的な作品のアドレスを取得します。
しかし、次のコードでテストすると:
GCC は、への呼び出しaddress_of
があいまいであると文句を言います。
単項*
は常に左辺値を返すという印象を受けました。その場合、右辺値のバージョンは考慮されるべきではありません。ここで何が起こっているのですか?
c++ - テンプレートパラメータの参照変数による問題
次の小さな例は私の問題を示しています。
エラーメッセージ(GCC):
エラー:'static void X :: xxx(T &&)[with T = int&]'はオーバーロードできません
エラー:with' static void X :: xxx(T&)[with T = int&]'</ p>
なんで?T = int&
---> inにT&
置き換えられますか?int&&
static void xxx(T& x)
質問に対する答えが「はい」の場合、次のようになります。
T&
は左辺値参照ではなく、右辺値参照になります。- そして、次のコードが機能するはずです。
しかし、そうではありませんでした:
エラーメッセージ(GCC):
エラー:'X :: xxx(int)'の呼び出しに一致する関数がありません<br>注:候補は次のとおりです:static void X :: xxx(T&)[with T = int&]
その場合T&
、withT = int&
は等しくT&&
なく、右辺値参照でもありません。しかし、そうでない場合、なぜ最初の例が機能しないのですか?(これは再帰的な問題です!)
しかし、同様の問題はポインター型では発生しませんでした。
この動作で参照が異なるのはなぜですか?
c++ - std::forward を使用する主な目的と、それによって解決される問題は何ですか?
完全転送では、名前付き右辺値参照を名前なし右辺std::forward
値参照に変換するために使用されます。それを行う目的は何ですか?&を左辺値のままにしておくと、呼び出された関数にどのような影響がありますか?t1
t2
inner
t1
t2
c++ - 右辺値参照
hereから Rvalue 参照を理解しようとしている間、私は2つのことを理解できません
- ベクトルに N 個の文字列がある場合、各コピーには N+1 個のメモリ割り当てと [...]
「N+1」のこの+1は何ですか?
2.筆者がいきなり以下のガイドラインにたどり着いた経緯
ガイドライン: 関数の引数をコピーしないでください。代わりに、それらを値で渡し、コンパイラーにコピーさせます。
何か不足していますか?