クラスがポインタをメンバーとして持つ場合に、破棄されるオブジェクトの内容をコピーするのではなく、移動させれば効率がよい。
それを可能とするのが右辺値参照である。
引数を右辺値参照でうける場合は && をつける。
Sample1 Move Constructor/ Assignment, ただしdouble* SomeClass::data
Sample1 std::moveによる強制的な移動
特に値型の返り値をもつクラスについてはコピーのコストを大きく削減することができる。
例えば以下のようなグローバル関数を持つクラス。
RotationalMatrixXの返り値をコピーするのは無駄であるが、返り値 m はRotationalMatrixXのローカル変数であるから、返り値を参照するわけにはいかない。
このような場合、返り値mを右辺値といい、move constructor、move assginmentがあればそちらを使う。
とりあえずは、move constructorとmove assignmentを定義・実装しておけば、引数が右辺値の場合はそちらが呼ばれるようになる。
それを可能とするのが右辺値参照である。
引数を右辺値参照でうける場合は && をつける。
Sample1 Move Constructor/ Assignment, ただしdouble* SomeClass::data
SomeClass::SomeClass( SomeClass&& src ) : data(nullptr) { data = src.data; //コピーせずにポインタをもらう。 src.data = nullptr; // ポインタはもらったのでdeleteせずにnullptrにしておく } SomeClass& SomeClass::operator=( SomeClass&& src ) { if( this != &src) { delete data; data = src.data; //コピーせずにポインタをもらう。 src.data = nullptr; // ポインタはもらったのでdeleteせずにnullptrにしておく } }
Sample1 std::moveによる強制的な移動
template<typename Ty> void Swap( Ty& a, Ty& b) { //Ty tmp = a; //これだとコピーが発生する Ty tmp = std::move(a); //Tyのmove constructorが呼ばれる。 a = std::move(b); //Tyのmove assignment( Ty::operator(Ty&& b) )が呼ばれる b = std::move(tmp); //同上。tmpの中身をbに移動させる。tmpの中身はなくなる }
特に値型の返り値をもつクラスについてはコピーのコストを大きく削減することができる。
例えば以下のようなグローバル関数を持つクラス。
class Matrix; Matrix RotationMatrixX(double radian) { Matrix m; //foo return m; }
RotationalMatrixXの返り値をコピーするのは無駄であるが、返り値 m はRotationalMatrixXのローカル変数であるから、返り値を参照するわけにはいかない。
このような場合、返り値mを右辺値といい、move constructor、move assginmentがあればそちらを使う。
とりあえずは、move constructorとmove assignmentを定義・実装しておけば、引数が右辺値の場合はそちらが呼ばれるようになる。
SomeClass MakeSomeClass(); int main() { SomeClass a, b; a = b; //copy assignment SomeClass c( a ); // copy constructor SomeClass d( MakeSomeClass() ); // move constructor a = MakeSomeClass(); // move assignment }
コメントをかく