【C++】コピーコンストラクタ
これまでの方法だと
- オブジェクトを関数に渡す
- 関数からオブジェクトを返す
ときに問題が発生した。
具体的には
- オブジェクトを関数に渡すと、そのオブジェクトのコピーが作成され、オブジェクトを受け付ける関数の引数として使用される
- 割り当てられたメモリのポインタを含むオブジェクトがある場合、コピーオブジェクトは元のオブジェクトと同じメモリを指す
- コピーオブジェクトでこのメモリに変更を加えると、元のオブジェクトに影響
- 関数の終了時に、コピーオブジェクトが破棄されデストラクタが呼び出されることで影響
- 割り当てられたメモリのポインタを含むオブジェクトがある場合、コピーオブジェクトは元のオブジェクトと同じメモリを指す
- 関数からオブジェクトを返す場合
- 関数から返す値を保持する一時オブジェクトを作成する
- 呼び出し元のルーチンに返した後は、スコープを外れデストラクタが呼び出される
- これが動的メモリの場合に問題が生じる
- 関数から返す値を保持する一時オブジェクトを作成する
- コピーコンストラクタは
- 1つのオブジェクトを使用して他のオブジェクトを初期化する方法を指定できる
- コピーコンストラクタは、そのオブジェクトを使って他のオブジェクトを初期化するときに呼出される
study152.cpp
#include <iostream> #include <cstdlib> using namespace std; class array { int *p; int size; public: array( int sz ) { p = new int[sz]; if( !p ) { exit(1); } size = sz; cout << "通常のコンストラクタを使う\n"; } ~array() { delete [] p; } array( const array &a ); void put( int i, int j ) { if ( i >= 0 && i < size ) { p[i] = j; } } int get( int i ) { return p[i]; } }; array::array( const array &a ) { size = a.size; p = new int[a.size]; if( !p ) { exit(1); } for( int i = 0; i < a.size; i++ ) { p[i] = a.p[i]; } cout << "コピーコンストラクタを使用\n"; } int main() { array num(10); for ( int i = 0; i < 10; ++i ) { num.put( i, i ); } for ( int i = 0; i < 10; ++i ) { cout << num.get(i); } cout << "\n"; array x = num; for ( int i = 0; i < 10; ++i ) { cout << x.get(i); } cout << "\n"; return 0; }
./study152 通常のコンストラクタを使う 0123456789 コピーコンストラクタを使用 0123456789
study156.cpp
#include <iostream> #include <cstring> #include <cstdlib> using namespace std; class strtype { char *p; public: strtype( char *s ); strtype( const strtype &o ); ~strtype() { delete [] p; } char *get() { return p; } }; strtype::strtype( char *s ) { int l; l = strlen(s) + 1; p = new char [l]; if ( !p ) { cout << "メモリ割り当てエラー\n"; exit(1); } strcpy( p, s ); } strtype::strtype( const strtype &o ) { int l; l = strlen(o.p) + 1; p = new char [l]; if ( !p ) { cout << "メモリ割り当てエラー\n"; exit(1); } strcpy( p, o.p ); } void show( strtype x ) { char *s; s = x.get(); cout << s << "\n"; } int main() { strtype a("Hello"), b("There"); show(a); show(b); return 0; }
- 関数へオブジェクトを引き渡すときにコピーが作成されるが、その設定をコピーコンストラクタが行う
- コピー作成時にコピー用のメモリを割り当てる
- show()終了時にスコープから外れ、x.pが指すメモリが開放されるが、これは関数に渡した元のオブジェクトのメモリとは異なる。