Cpp 右辺値参照 新しいページはコチラ
提供: yonewiki
(→右辺値参照) |
|||
1行: | 1行: | ||
+ | [[C PlusPlus#C++からの技術|C++]]に戻る | ||
+ | |||
+ | |||
<table class="mbox-small" style="border:1px solid #aaa; background-color:#f9f9f9; width:22em;" id="RealTitleBanner"> | <table class="mbox-small" style="border:1px solid #aaa; background-color:#f9f9f9; width:22em;" id="RealTitleBanner"> | ||
<tr> | <tr> | ||
<td style="width:1px;"></td> | <td style="width:1px;"></td> | ||
− | <td class="mbox-text plainlist" style="">本来の表記は「<b><span id="RealTitle" style="font-size:large;">C++ 右辺値参照</span></b>」です。この記事に付けられた題名は{{記事名の制約}}から不正確なものとなっています。</td> | + | <td class="mbox-text plainlist" style="">本来の表記は「<b><span id="RealTitle" style="font-size:large;">C++(Cpp) 右辺値参照</span></b>」です。この記事に付けられた題名は{{記事名の制約}}から不正確なものとなっています。</td> |
</tr> | </tr> | ||
</table> | </table> | ||
8行: | 11行: | ||
<br /> | <br /> | ||
== '''右辺値参照''' == | == '''右辺値参照''' == | ||
+ | |||
[[Cpp 参照]]の特殊なパターンとして右辺値参照があります。あまり知られていないという点で特殊と記述しましたが、知っているひとからすれば、ごく自然なC++の言語仕様の一部に過ぎないです。 | [[Cpp 参照]]の特殊なパターンとして右辺値参照があります。あまり知られていないという点で特殊と記述しましたが、知っているひとからすれば、ごく自然なC++の言語仕様の一部に過ぎないです。 | ||
34行: | 38行: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int nSize; |
int&& rrefnSize = nSize; //これは駄目。 | int&& rrefnSize = nSize; //これは駄目。 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
46行: | 50行: | ||
以下は[[C キャスト | キャスト]]による明示的な右辺値参照代入の指定です。 | 以下は[[C キャスト | キャスト]]による明示的な右辺値参照代入の指定です。 | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int nSize; |
int&& rrefnSize = static_cast<int&&>(nSize); //これはOK。 | int&& rrefnSize = static_cast<int&&>(nSize); //これはOK。 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
52行: | 56行: | ||
<syntaxhighlight lang="cpp"> | <syntaxhighlight lang="cpp"> | ||
− | int | + | int nSize; |
int&& rrefnSize = std::move(nSize); //キャストと同じで、OK。 | int&& rrefnSize = std::move(nSize); //キャストと同じで、OK。 | ||
</syntaxhighlight> | </syntaxhighlight> | ||
192行: | 196行: | ||
crightrefsampleInst003->getStrValueAddress(), | crightrefsampleInst003->getStrValueAddress(), | ||
crightrefsampleInst004->getStrValueAddress()); | crightrefsampleInst004->getStrValueAddress()); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
printf("\n"); | printf("\n"); | ||
226行: | 225行: | ||
{ | { | ||
private: | private: | ||
− | |||
char* m_pcStrValue; | char* m_pcStrValue; | ||
+ | public: | ||
int Function(){return 1;}; | int Function(){return 1;}; | ||
CRightRefSample(void); | CRightRefSample(void); | ||
313行: | 312行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | 非常に長いサンプルになってしまいましたが、こんな感じでClassのメンバ変数を入れ替えるようなプログラム(staticで定義したメンバ関数swap 静的メンバ関数はオブジェクトからでなくても呼べる関数です。別で詳細は説明の予定。thisポインタが使えないクラスの中にあるだけの関数CRightSample::swap(…)のように呼び出すものです。)を作ってみました。算術演算子 = をオーバロード(関数として定義)していまして、(CRightRefSampleのインスタンス) = の後ろに(CRightRefSampleのインスタンス)が設定された場合の関数と(CRightRefSampleのインスタンス)が右辺値参照として設定されている場合の関数の2つをオーバロードしています。同じ代入演算子でも引数が右辺値参照のときはムーブ、引数が参照のときはコピーのように使い分けることができます。右辺値参照の変数は使わなくなる予定の変数ですので、引数で受け取った変数をコピーするのではなくムーブしてしまうようにして利用します。特にswapのような入れ替えではポインタの交換だけを行うことで入れ替えられますので、AとBの入れ替え処理では入れ替え用の一時的な変数に対してAをムーブし、ムーブしおわったAにBの値をムーブ、そして一時的に作った変数からBへムーブという具合に3回のムーブによりポインタの入れ替えができて内容を交換できます。今回はひとつのメンバ変数のみの入れ替えサンプルですが、クラスの中の要素が文字列のような配列であったり、構造体、クラスといったようなもっと複雑なデータを保持している場合にムーブすることでデータの受け渡しをすることができます。コピーを作らなくてもいいような処理にはムーブは資源の節約にもなるし、無駄な処理が無いため処理速度も改善されます。ムーブのような作業は別に右辺値参照を使うことなくできますので、必ずしも右辺値参照が必要なわけではないですが、参照を引数にした場合の処理と分けることができるのが特徴です。今回はstd:: | + | 非常に長いサンプルになってしまいましたが、こんな感じでClassのメンバ変数を入れ替えるようなプログラム(staticで定義したメンバ関数swap 静的メンバ関数はオブジェクトからでなくても呼べる関数です。別で詳細は説明の予定。thisポインタが使えないクラスの中にあるだけの関数CRightSample::swap(…)のように呼び出すものです。)を作ってみました。算術演算子 = をオーバロード(関数として定義)していまして、(CRightRefSampleのインスタンス) = の後ろに(CRightRefSampleのインスタンス)が設定された場合の関数と(CRightRefSampleのインスタンス)が右辺値参照として設定されている場合の関数の2つをオーバロードしています。同じ代入演算子でも引数が右辺値参照のときはムーブ、引数が参照のときはコピーのように使い分けることができます。右辺値参照の変数は使わなくなる予定の変数ですので、引数で受け取った変数をコピーするのではなくムーブしてしまうようにして利用します。特にswapのような入れ替えではポインタの交換だけを行うことで入れ替えられますので、AとBの入れ替え処理では入れ替え用の一時的な変数に対してAをムーブし、ムーブしおわったAにBの値をムーブ、そして一時的に作った変数からBへムーブという具合に3回のムーブによりポインタの入れ替えができて内容を交換できます。今回はひとつのメンバ変数のみの入れ替えサンプルですが、クラスの中の要素が文字列のような配列であったり、構造体、クラスといったようなもっと複雑なデータを保持している場合にムーブすることでデータの受け渡しをすることができます。コピーを作らなくてもいいような処理にはムーブは資源の節約にもなるし、無駄な処理が無いため処理速度も改善されます。ムーブのような作業は別に右辺値参照を使うことなくできますので、必ずしも右辺値参照が必要なわけではないですが、参照を引数にした場合の処理と分けることができるのが特徴です。今回はstd::moveのような関数であえて右辺値として扱うことでムーブを実現していますが、右辺値参照を引数にしている部分に引数にスタティックなクラスメンバ関数や関数を定義してクラスのインスタンスを戻り値とするような関数を作った場合に純粋な右辺値が登場しますが、そのような場合でも同じようにムーブされて問題ない処理になるはずです。右辺値参照を引数にとるムーブコンストラクタや代入演算子のオーバロードによるムーブを活用できることを知っておくことで、よりよいクラスの使い方が可能となります。同じような関数が多くなりがちですが、このあたりはテンプレートの活用によりさらにコーディングの効率はあげられると思います。ここでは、あまりややこしくならないように最小限のクラス化と、最小限のテンプレートクラスの利用でメモを作成しています。 |
+ | |||
+ | |||
+ | ムーブコンストラクタはコピーコンストラクタの引数が通常の参照であったのに対して、元の値をとっておかないような使い方として、引数を右辺値参照型にしているようなコンストラクタになっています。 | ||
+ | |||
+ | |||
+ | このプログラムを理解するにはオブジェクト(インスタンス)、ポインタ、nullptr、文字列操作、参照、クラス(コンストラクタ デストラクタ 静的メンバ関数 演算子のオーバロード オーバロード インライン関数)を理解しておく必要があります。 | ||
371行: | 376行: | ||
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | [[C PlusPlus#C++からの技術|C++]]に戻る |