[解決済み] C++11のT&&(ダブルアンパサンド)の意味とは?
質問
C++11の新機能を調べていて気づいたのは、変数を宣言するときにアンパサンドを2つ使うことです。
T&& var
.
とりあえず、この獣はなんという名前なのだろうか?Googleでこんな句読点の検索ができるようになればいいのに。
具体的にはどのようなものかというと の意味は?
一見すると、二重参照(C言語のダブルポインタのようなもの)のように見えます。
T** var
) が、そのユースケースが思い浮かばないのです。
どのように解決するのか?
を宣言しています。 rvalue リファレンス (規格提案書doc)。
ここでは、rvalueについて紹介します。 リファレンス .
Microsoftの標準ライブラリの1つで、rvalue参照について深く掘り下げた素晴らしい記事があります。 開発者 .
注意 MSDN のリンク先の記事("Rvalue References: C++0x Features in VC10, Part 2")は、Rvalue 参照について非常にわかりやすく紹介していますが、Rvalue 参照について、かつて C++11 標準草案では正しかったが、最終的には正しくないという記述をしています! 具体的には、rvalue参照はlvalueにバインドできると様々な箇所で述べており、これはかつて真実であったが、変更された。(例: int x; int &&rrx = x; もはやGCCではコンパイルできない) - drawnbarbs Jul 13 '14 at 16:12
C++03の参照(C++11ではlvalue参照と呼ばれるようになった)の最大の違いは、constでなくてもtemporaryのようにrvalueにバインドできることです。 したがって、この構文が合法になりました。
T&& r = T();
rvalue参照は、主に次のようなものを提供する。
移動セマンティクス . 通常の const-lvalue 参照の代わりに rvalue 参照を取る移動コンストラクタと移動代入演算子が定義できるようになりました。 移動はコピーと同様に機能しますが、移動元を変更しないことが条件ではありません。実際、通常は移動元を変更して、移動したリソースを所有しないようにします。 これは、特に標準的なライブラリ実装において、余計なコピーを排除するのに適しています。
例えば、コピーコンストラクタは次のようなものである。
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
このコンストラクタにテンポラリが渡された場合、テンポラリは破棄されることが分かっているので、コピーは不要になります。 C++03 では、テンポラリを渡されたかどうかを判断できないため、コピーを防止する方法はありません。 C++11では、移動コンストラクタをオーバーロードすることができます。
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
ここで大きな違いに注目してください。移動コンストラクタは実際に引数を変更します。 これにより、一時的なオブジェクトを構築中のオブジェクトに効果的に移動させ、不要なコピーを排除することができます。
移動コンストラクタはテンポラリや、非恒等式の l 値参照から、明示的に
std::move
関数を使用します(変換を行うだけです)。 次のコードは、どちらも移動コンストラクタを起動して
f1
と
f2
:
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
パーフェクトフォワーディング rvalue参照により、テンプレート化された関数の引数を適切に転送することができます。 例えば、このファクトリー関数を考えてみましょう。
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
を呼び出すと
factory<foo>(5)
であることが推論されます。
int&
を指定しても、リテラル5にはバインドされません。
foo
のコンストラクタは
int
. さて、代わりに
A1 const&
しかし、もし
foo
はコンストラクタの引数を非恒等式参照で取るのでしょうか? 真に汎用的なファクトリー関数を作るには、ファクトリーをオーバーロードして
A1&
と
A1 const&
. しかし、パラメータが1つ増えるごとに、必要なオーバーロードが2倍になってしまいます。
rvalue参照は、標準ライブラリで
std::forward
関数で、lvalue/rvalue 参照を適切に転送することができます。 の詳細については
std::forward
の動作は
この素晴らしい回答
.
これにより、次のようにファクトリー関数を定義することができます。
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
これで、引数のrvalue/lvalueらしさが保たれたまま
T
のコンストラクタを使用します。 つまり、factoryがrvalueで呼び出された場合。
T
のコンストラクタがr値で呼び出されます。 もしfactoryがl値で呼ばれた場合。
T
のコンストラクタは lvalue で呼び出されます。 このように改良されたファクトリー機能は、ある特別なルールによって機能しています。
関数パラメータの型が
形式
T&&
ここで
T
はテンプレート
パラメータ、そして関数の引数
の型の lvalue です。
A
の場合、その型は
A&
は
はテンプレート引数の推論に使用されます。
よって、factoryはこのように使うことができる。
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
重要な rvalue リファレンスプロパティ :
- 過負荷解消のため。 lvalues は lvalue 参照へのバインディングを好み、rvalues は rvalue 参照へのバインディングを好みます。 . そのため、一時演算子はコピー演算子や代入演算子よりも、移動演算子や移動代入演算子を呼び出すことを好むのです。
-
rvalue参照は、rvalueおよび暗黙の変換の結果であるtemporaryに暗黙のうちにバインドされます。
... すなわち
float f = 0f; int&& i = f;
は、floatがintに暗黙のうちに変換されるため、うまく形成されています。この参照は、変換の結果である一時的なものです。 -
名前付きrvalueの参照はlvalueです。 名前のないrvalue参照はrvalueです。
の理由を理解する上で重要です。
std::move
の呼び出しが必要です。foo&& r = foo(); foo f = std::move(r);
関連
-
[解決済み】C++の余分な資格エラー
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] ルール・オブ・スリーとは?
-
[解決済み] コピーアンドスワップ慣用句とは?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
-
[解決済み】C++11のラムダ式って何?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み】リンカーエラーです。"リンカ入力ファイルはリンクが行われていないため未使用"、そのファイル内の関数への未定義参照
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む