Cpp 右辺値参照 新しいページはコチラ
提供: yonewiki
(→右辺値参照) |
(→右辺値参照) |
||
108行: | 108行: | ||
このような右辺値戻り値を引数にとるような関数で、ポインタ変数のアドレスだけを移動させることによる、付け替え関数を作ることができます。言葉での説明ではイメージできないと思うので、実際にやってみた方がいいですね。 | このような右辺値戻り値を引数にとるような関数で、ポインタ変数のアドレスだけを移動させることによる、付け替え関数を作ることができます。言葉での説明ではイメージできないと思うので、実際にやってみた方がいいですね。 | ||
+ | Mainプログラム | ||
+ | <syntaxhighlight lang="cpp" line start="1"> | ||
+ | #include "stdafx.h" | ||
+ | #include "RightRefSample.h" | ||
− | + | int _tmain(int argc, _TCHAR* argv[]) | |
+ | { | ||
+ | printf("★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\n"); | ||
+ | printf("★★開始\n"); | ||
+ | printf("\n"); | ||
+ | printf("★オリジナルのクラス生成 Inst001\n"); | ||
+ | CRightRefSample* crightrefsampleInst001 = new CRightRefSample("001"); | ||
+ | |||
+ | printf("\n"); | ||
+ | printf("★2個目のクラス生成 Inst001を初期値でコピーしたクラスInst002\n"); | ||
+ | CRightRefSample* crightrefsampleInst002 = new CRightRefSample(*crightrefsampleInst001); | ||
+ | |||
+ | printf("\n"); | ||
+ | printf("★3個目のクラス生成Inst003\n"); | ||
+ | CRightRefSample* crightrefsampleInst003 = new CRightRefSample("003"); | ||
+ | |||
+ | printf("\n"); | ||
+ | printf("★4個目のクラス生成Inst004\n"); | ||
+ | CRightRefSample* crightrefsampleInst004 = new CRightRefSample("004"); | ||
+ | |||
+ | printf("★状態表示\n"); | ||
+ | printf("★m_pStrChar:001->%06x 002->%06x 003->%06x 004->%06x\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | printf("★m_pStrChar:001->%6s 002->%6s 003->%6s 004->%6s\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | |||
+ | |||
+ | printf("\n"); | ||
+ | printf("★3個目に生成したInst003へInst001をコピー\n"); | ||
+ | *crightrefsampleInst003 = *crightrefsampleInst001; | ||
+ | |||
+ | printf("★状態表示\n"); | ||
+ | printf("★m_pStrChar:001->%06x 002->%06x 003->%06x 004->%06x\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | printf("★m_pStrChar:001->%6s 002->%6s 003->%6s 004->%6s\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | |||
+ | |||
+ | printf("\n"); | ||
+ | printf("★Inst001とInst003を交換\n"); | ||
+ | CRightRefSample::swap(*crightrefsampleInst001,*crightrefsampleInst003); | ||
+ | printf("★状態表示\n"); | ||
+ | printf("★m_pStrChar:001->%06x 002->%06x 003->%06x 004->%06x\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | printf("★m_pStrChar:001->%6s 002->%6s 003->%6s 004->%6s\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | |||
+ | printf("\n"); | ||
+ | printf("★4個目に生成したInst004へInst001をムーブ\n"); | ||
+ | *crightrefsampleInst004 = std::move(*crightrefsampleInst001); | ||
+ | printf("★状態表示\n"); | ||
+ | printf("★m_pStrChar:001->%06x 002->%06x 003->%06x 004->%06x\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | printf("★m_pStrChar:001->%6s 002->%6s 003->%6s 004->%6s\n", | ||
+ | crightrefsampleInst001->getStrValueAddress(), | ||
+ | crightrefsampleInst002->getStrValueAddress(), | ||
+ | crightrefsampleInst003->getStrValueAddress(), | ||
+ | crightrefsampleInst004->getStrValueAddress()); | ||
+ | |||
+ | //crightrefsampleInst004 = crightrefsampleInst001;//crightrefsampleInst001が右辺値の形式ではないので、演算子=の上書き定義は呼ばれない。 | ||
+ | //右辺値として扱われるには、CRightRefSample型の戻り値を返す関数を指定したとき。 | ||
+ | //crightrefsampleInst004 = crightrefsampleInst001->ref(); | ||
+ | |||
+ | |||
+ | printf("\n"); | ||
+ | printf("★生成したインスタンスの全削除手動\n"); | ||
+ | printf("Inst001 Delete\n"); | ||
+ | delete crightrefsampleInst001; | ||
+ | |||
+ | printf("Inst002 Delete\n"); | ||
+ | delete crightrefsampleInst002; | ||
+ | |||
+ | printf("Inst003 Delete\n"); | ||
+ | delete crightrefsampleInst003; | ||
+ | |||
+ | printf("Inst004 Delete\n"); | ||
+ | delete crightrefsampleInst004; | ||
+ | printf("★★終了\n"); | ||
+ | printf("★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\n"); | ||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | RightRefSample.h | ||
+ | <syntaxhighlight lang="cpp" line start="1"> | ||
+ | #pragma once | ||
+ | #include <iostream> | ||
+ | |||
+ | using namespace std; | ||
+ | |||
+ | class CRightRefSample | ||
+ | { | ||
+ | private: | ||
+ | public: | ||
+ | char* m_pcStrValue; | ||
+ | int Function(){return 1;}; | ||
+ | CRightRefSample(void); | ||
+ | CRightRefSample(const char* pconstcDefaultValue); | ||
+ | CRightRefSample(const CRightRefSample& refcrightrefsampleInst ); | ||
+ | CRightRefSample(CRightRefSample&& rrefcrightrefsampleInst ); | ||
+ | CRightRefSample& operator= (const CRightRefSample& refcrightrefsampleInst); | ||
+ | CRightRefSample& operator= (CRightRefSample&& refcrightrefsampleInst); | ||
+ | |||
+ | static void swap(CRightRefSample& refcrightrefsampleA,CRightRefSample& refcrightrefsampleB); | ||
+ | char* getStrValueAddress(){return m_pcStrValue;}; | ||
+ | |||
+ | ~CRightRefSample(void); | ||
+ | }; | ||
+ | </syntaxhighlight> | ||
+ | RightRefSample.cpp | ||
+ | <syntaxhighlight lang="cpp" line start="1"> | ||
+ | #include "stdafx.h" | ||
+ | #include "RightRefSample.h" | ||
+ | |||
+ | //コンストラクタ | ||
+ | CRightRefSample::CRightRefSample(void) | ||
+ | { | ||
+ | printf("%06x: CRightRefSample (void)Constructor :%s\n", this, __FUNCTION__); | ||
+ | m_pcStrValue = new char[1024]; | ||
+ | strcpy_s(m_pcStrValue, 1024, "初期値"); | ||
+ | |||
+ | } | ||
+ | |||
+ | CRightRefSample::CRightRefSample(const char* pconstcDefaultValue){ | ||
+ | printf("%06x: CRightRefSample (const char)Constructor :%s\n", this, __FUNCTION__); | ||
+ | |||
+ | m_pcStrValue = new char[strlen(pconstcDefaultValue) + 1]; | ||
+ | strcpy_s(m_pcStrValue, strlen(pconstcDefaultValue) + 1, pconstcDefaultValue); | ||
+ | } | ||
+ | |||
+ | //コピーコンストラクタ | ||
+ | CRightRefSample::CRightRefSample(const CRightRefSample& refcrightrefsampleInst ){ | ||
+ | printf("%06x: CRightRefSample (Ref)CopyConstructor :%s\n", this, __FUNCTION__); | ||
+ | m_pcStrValue = new char[1024]; | ||
+ | strcpy_s(m_pcStrValue, 1024, refcrightrefsampleInst.m_pcStrValue); | ||
+ | } | ||
+ | |||
+ | //ムーブコンストラクタ | ||
+ | CRightRefSample::CRightRefSample(CRightRefSample&& rrefcrightrefsampleInst ){ | ||
+ | |||
+ | printf("%06x: CRightRefSample (RightRef)MoveConstructor:%s\n", this, __FUNCTION__); | ||
+ | m_pcStrValue = rrefcrightrefsampleInst.m_pcStrValue;//新しいクラスにだけ | ||
+ | rrefcrightrefsampleInst.m_pcStrValue = nullptr; | ||
+ | } | ||
+ | //=代入演算子の後ろに参照引数でコピー処理 | ||
+ | CRightRefSample& CRightRefSample::operator= (const CRightRefSample& refcrightrefsampleInst){ | ||
+ | delete[] m_pcStrValue; | ||
+ | |||
+ | printf("%06x: CRightRefSample (Ref)operator= :%s\n", this, __FUNCTION__); | ||
+ | m_pcStrValue = new char[strlen(refcrightrefsampleInst.m_pcStrValue) + 1]; | ||
+ | strcpy_s(m_pcStrValue,strlen(refcrightrefsampleInst.m_pcStrValue) + 1,refcrightrefsampleInst.m_pcStrValue); | ||
+ | |||
+ | return *this; | ||
+ | } | ||
+ | //=代入演算子の後ろに右辺値参照引数でムーブ処理 | ||
+ | CRightRefSample& CRightRefSample::operator= (CRightRefSample&& refcrightrefsampleInst){ | ||
+ | delete[] m_pcStrValue; | ||
+ | |||
+ | printf("%06x: CRightRefSample (RightRef)operator= :%s\n", this, __FUNCTION__); | ||
+ | m_pcStrValue = refcrightrefsampleInst.m_pcStrValue; | ||
+ | refcrightrefsampleInst.m_pcStrValue = nullptr; | ||
+ | |||
+ | return *this; | ||
+ | } | ||
+ | //クラス変数の入れ替えムーブ版 | ||
+ | void CRightRefSample::swap(CRightRefSample& refcrightrefsampleA,CRightRefSample& refcrightrefsampleB){ | ||
+ | printf("%06x: CRightRefSample (Ref, Ref)swap :%s\n", 0, __FUNCTION__); | ||
+ | CRightRefSample crightrefsampleTemp = std::move(refcrightrefsampleA);//ムーブコンストラクタ | ||
+ | refcrightrefsampleA = std::move(refcrightrefsampleB);//代入演算子ムーブ処理 | ||
+ | refcrightrefsampleB = std::move(crightrefsampleTemp);//代入演算子ムーブ処理 | ||
+ | } | ||
+ | |||
+ | //デストラクタ | ||
+ | CRightRefSample::~CRightRefSample(void) | ||
+ | { | ||
+ | printf("%06x: CRightRefSample (void)Destructor :addres->%06x name->%s\n", this, m_pcStrValue, __FUNCTION__); | ||
+ | delete[] m_pcStrValue; | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | 非常に長いサンプルになってしまいましたが、こんな感じでClassのメンバ変数を入れ替えるようなプログラム(staticで定義したメンバ関数swap 静的メンバ関数はオブジェクトからでなくても呼べる関数です。別で詳細は説明の予定。thisポインタが使えないクラスの中にあるだけの関数CRightSample::swap(…)のように呼び出すものです。)を作ってみました。算術演算子 = をオーバロード(関数として定義)していまして、(CRightRefSampleのインスタンス) = の後ろに(CRightRefSampleのインスタンス)が設定された場合の関数と(CRightRefSampleのインスタンス)が右辺値参照として設定されている場合の関数の2つをオーバロードしています。同じ代入演算子でも引数が右辺値参照のときはムーブ、引数が参照のときはコピーのように使い分けることができます。右辺値参照の変数は使わなくなる予定の変数ですので、引数で受け取った変数をコピーするのではなくムーブしてしまうようにして利用します。特にswapのような入れ替えではポインタの交換だけを行うことで入れ替えられますので、AとBの入れ替え処理では入れ替え用の一時的な変数に対してAをムーブし、ムーブしおわったAにBの値をムーブ、そして一時的に作った変数からBへムーブという具合に3回のムーブによりポインタの入れ替えができて内容を交換できます。今回はひとつのメンバ変数のみの入れ替えサンプルですが、クラスの中の要素が文字列のような配列であったり、構造体、クラスといったようなもっと複雑なデータを保持している場合にムーブすることでデータの受け渡しをすることができます。コピーを作らなくてもいいような処理にはムーブは資源の節約にもなるし、無駄な処理が無いため処理速度も改善されます。ムーブのような作業は別に右辺値参照を使うことなくできますので、必ずしも右辺値参照が必要なわけではないですが、参照を引数にした場合の処理と分けることができるのが特徴です。今回はstd::moveのような関数であえて右辺値として扱うことでムーブを実現していますが、右辺値参照を引数にしている部分に引数にスタティックなクラスメンバ関数や関数を定義してクラスのインスタンスを戻り値とするような関数を作った場合に純粋な右辺値が登場しますが、そのような場合でも同じようにムーブされて問題ない処理になるはずです。右辺値参照を引数にとるムーブコンストラクタや代入演算子のオーバロードによるムーブを活用できることを知っておくことで、よりよいクラスの使い方が可能となります。 | ||
+ | |||
+ | |||
+ | サンプルプログラムの出力結果は以下のとおりです。 | ||
+ | <syntaxhighlight lang="text"> | ||
+ | ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | ★★開始 | ||
+ | |||
+ | ★オリジナルのクラス生成 Inst001 | ||
+ | 338240: CRightRefSample (const char)Constructor :CRightRefSample::CRightRefSample | ||
+ | |||
+ | ★2個目のクラス生成 Inst001を初期値でコピーしたクラスInst002 | ||
+ | 3382a0: CRightRefSample (Ref)CopyConstructor :CRightRefSample::CRightRefSample | ||
+ | |||
+ | ★3個目のクラス生成Inst003 | ||
+ | 3382d0: CRightRefSample (const char)Constructor :CRightRefSample::CRightRefSample | ||
+ | |||
+ | ★4個目のクラス生成Inst004 | ||
+ | 338330: CRightRefSample (const char)Constructor :CRightRefSample::CRightRefSample | ||
+ | ★状態表示 | ||
+ | ★m_pStrChar:001->338270 002->33dbd0 003->338300 004->338360 | ||
+ | ★m_pStrChar:001-> 001 002-> 001 003-> 003 004-> 004 | ||
+ | |||
+ | ★3個目に生成したInst003へInst001をコピー | ||
+ | 3382d0: CRightRefSample (Ref)operator= :CRightRefSample::operator = | ||
+ | ★状態表示 | ||
+ | ★m_pStrChar:001->338270 002->33dbd0 003->338300 004->338360 | ||
+ | ★m_pStrChar:001-> 001 002-> 001 003-> 001 004-> 004 | ||
+ | |||
+ | ★Inst001とInst003を交換 | ||
+ | 000000: CRightRefSample (Ref, Ref)swap :CRightRefSample::swap | ||
+ | 24f908: CRightRefSample (RightRef)MoveConstructor:CRightRefSample::CRightRefSample | ||
+ | 338240: CRightRefSample (RightRef)operator= :CRightRefSample::operator = | ||
+ | 3382d0: CRightRefSample (RightRef)operator= :CRightRefSample::operator = | ||
+ | 24f908: CRightRefSample (void)Destructor :addres->000000 name->CRightRefSample::~CRightRefSample | ||
+ | ★状態表示 | ||
+ | ★m_pStrChar:001->338300 002->33dbd0 003->338270 004->338360 | ||
+ | ★m_pStrChar:001-> 001 002-> 001 003-> 001 004-> 004 | ||
+ | |||
+ | ★4個目に生成したInst004へInst001をムーブ | ||
+ | 338330: CRightRefSample (RightRef)operator= :CRightRefSample::operator = | ||
+ | ★状態表示 | ||
+ | ★m_pStrChar:001->000000 002->33dbd0 003->338270 004->338300 | ||
+ | ★m_pStrChar:001->(null) 002-> 001 003-> 001 004-> 001 | ||
+ | |||
+ | ★生成したインスタンスの全削除手動 | ||
+ | Inst001 Delete | ||
+ | 338240: CRightRefSample (void)Destructor :addres->000000 name->CRightRefSample::~CRightRefSample | ||
+ | Inst002 Delete | ||
+ | 3382a0: CRightRefSample (void)Destructor :addres->33dbd0 name->CRightRefSample::~CRightRefSample | ||
+ | Inst003 Delete | ||
+ | 3382d0: CRightRefSample (void)Destructor :addres->338270 name->CRightRefSample::~CRightRefSample | ||
+ | Inst004 Delete | ||
+ | 338330: CRightRefSample (void)Destructor :addres->338300 name->CRightRefSample::~CRightRefSample | ||
+ | |||
+ | ★★終了 | ||
+ | ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | ||
+ | </syntaxhighlight> |