9

最初: と はどこにstd::move定義std::forwardされていますか? それらが何をするかは知っていますが、それらを含めるために標準ヘッダーが必要であるという証拠を見つけることができません。gcc44std::moveでは、利用できる場合と利用できない場合があるため、明確な include ディレクティブが役立ちます。

移動セマンティクスを実装する場合、ソースはおそらく未定義の状態のままになります。この状態は、オブジェクトの有効な状態である必要がありますか? 明らかに、オブジェクトのデストラクタを呼び出すことができる必要があり、クラスが公開する手段によってオブジェクトを代入できる必要があります。しかし、他の操作は有効である必要がありますか? 私が求めているのは、クラスが特定の不変条件を保証している場合、ユーザーがそれらを気にしないと言ったときに、それらの不変条件を強制するように努力する必要があると思いますか?

次: 移動セマンティクスを気にしない場合、関数パラメーターを処理するときに右辺値参照よりも非 const 参照が優先される原因となる制限はありますか? void function(T&);呼び出し元のvoid function(T&&);観点からは、関数に一時的な値を渡すことができると便利な場合があるため、実行可能な場合はいつでもそのオプションを許可する必要があるようです。また、右辺値参照はそれ自体が左辺値であるため、誤ってコピー コンストラクターの代わりにムーブ コンストラクターなどを呼び出すことはできません。マイナス面は見当たりませんが、マイナス面があることは確かです。

それが私の最後の質問につながります。一時変数を非 const 参照にバインドすることはまだできません。ただし、それらを非 const 右辺値参照にバインドできます。そして、その参照を別の関数で非 const 参照として渡すことができます。

void function1(int& r) { r++; }
void function2(int&& r) { function1(r); }
int main() { 
    function1(5); //bad
    function2(5); //good
}

何もしないという事実に加えて、そのコードに何か問題がありますか? 右辺値参照を変更することは、それらの存在の全体的なポイントであるため、私の直感はもちろんそうではありません。そして、渡された値が正当に const である場合、コンパイラはそれをキャッチして怒鳴ります。しかしどう見ても、これは何らかの理由で導入されたと思われる仕組みの回避策であるため、私が愚かなことをしていないことを確認したいと思います。

4

3 に答える 3

9

最初: std::move と std::forward はどこで定義されていますか?

20.3ユーティリティ コンポーネントを参照してください<utility>


移動セマンティクスを実装する場合、ソースはおそらく未定義の状態のままになります。この状態は、オブジェクトの有効な状態である必要がありますか?

明らかに、オブジェクトは依然として破壊可能である必要があります。しかし、それ以上に、まだ割り当て可能であることは良い考えだと思います。標準は、「MoveConstructible」と「MoveAssignable」を満たすオブジェクトについて次のように述べています。

[ 注: rv は有効なオブジェクトのままです。その状態は特定されていません。— エンドノート]

これは、前提条件を示さない操作にオブジェクトが引き続き参加できることを意味すると思います。これには、CopyConstructible、CopyAssignable、Destructible などが含まれます。これは、コア言語の観点から、独自のオブジェクトには何も必要ないことに注意してください。これらの要件を示す標準ライブラリ コンポーネントに触れた場合にのみ、要件が発生します。


次: 移動セマンティクスを気にしない場合、関数パラメーターを処理するときに右辺値参照よりも非 const 参照が優先される原因となる制限はありますか?

残念ながら、これはパラメーターが関数テンプレートにあり、テンプレート パラメーターを使用するかどうかに大きく依存します。

void f(int const&); // takes all lvalues and const rvalues
void f(int&&); // can only accept nonconst rvalues

ただし、関数テンプレートの場合

template<typename T> void f(T const&);
template<typename T> void f(T&&);

U&2 番目のテンプレートは、左辺値で呼び出された後、合成された宣言のパラメーターとして、非 const 左辺値の型 (およびより一致する) とU const&const 左辺値の型 (およびあいまいになる)を持つため、それを言うことはできません。私の知る限り、その 2 番目のあいまいさを解消するための半順序規則はありません。しかし、これはすでに知られています。

--編集--

その問題報告にもかかわらず、2 つのテンプレートがあいまいであるとは思いません。部分的な順序付けにより、最初のテンプレートがより特殊化されます。参照修飾子と を取り除いた後、const両方の型が同じであることがわかり、最初のテンプレートが const への参照を持っていることがわかります。標準は言う ( 14.9.2.4)

与えられた型について、演繹が両方向で成功した場合 (つまり、上記の変換後に型が同一である場合)、および引数テンプレートからの型がパラメーター テンプレートからの型よりも cv 修飾されている場合 (上記のように) )そのタイプは、他のタイプよりも専門的であると見なされます。

考慮されている型ごとに、特定のテンプレートが少なくともすべての型に特化しており、一部の型のセットに特化しており、もう一方のテンプレートがどの型にも特化していないか、少なくともどの型にも特化していない場合、指定されたテンプレートは、他のテンプレートよりも特化されています。

これにより、T const&テンプレートは部分的な順序付けの勝者になります (そして、GCC は実際にそれを選択するのが正しいです)。

--編集終了--


それが私の最後の質問につながります。一時変数を非 const 参照にバインドすることはまだできません。ただし、それらを非 const 右辺値参照にバインドできます。

これは、この記事でうまく説明されています。を使用する 2 番目の呼び出しfunction2は、非 const 右辺値のみを取ります。プログラムの残りの部分は、後でこれらの右辺値にアクセスできなくなるため、それらが変更されても気付かないでしょう! また、渡すのはクラス型ではないため、非表示の一時が作成されて右辺値参照5に渡されます。int&&コード呼び出しfunction2は、ここでその非表示オブジェクトにアクセスできないため、変更に気づきません。

別の状況は、これを行う場合です。

SomeComplexObject o;
function2(move(o));

移動することを明示的に要求したoため、その移動仕様に従って変更されます。ただし、移動は論理的に非変更操作です (記事を参照)。これは、移動するかどうかを呼び出し元のコードから観察できないことを意味します。

SomeComplexObject o;
moveit(o); // #1
o = foo;

動く線を消しても上書きされるので動作は同じです。ただし、これは、 と呼び出し元のコードの間の暗黙の契約を破るため、o移動後の値を使用するコードはbadであることを意味します。moveitしたがって、標準では、コンテナから移動したコンテナの具体的な値について仕様を定めていません。

于 2010-04-05T09:52:32.683 に答える
4

std::move と std::forward はどこで定義されていますか?

std::movestd::forward宣言されてい<utility>ます。セクション 20.3[ユーティリティ] の冒頭にある概要を参照してください。

移動セマンティクスを実装する場合、ソースはおそらく未定義の状態のままになります。

もちろん、移動コンストラクターと移動代入演算子をどのように実装するかによって異なります。ただし、オブジェクトを標準コンテナで使用する場合は、オブジェクトは有効なままであるが、未指定の状態のままである、つまり確実に破棄できるという概念に従う必要がMoveConstructibleあります。MoveAssignable

于 2010-04-05T09:43:14.587 に答える
2

ユーティリティに含まれる


これは、右辺値について読んだ記事です。

休むことはできません、ごめんなさい。

于 2010-04-05T09:42:27.667 に答える