[C++]深いコピーと浅いコピー
5468 ワード
c++のクラスにポインタタイプが含まれている場合は、コピーを行う際に深いコピーと浅いコピーの問題に注意してください.
(1)浅いコピーは「ビットコピー」方式を採用する.int、floatなどの基礎タイプについては、直接copyすることができます.
ただし、ポインタタイプでは、copyの場合、浅いコピーはポインタが指すアドレスのみをcopyし、そのアドレスを作成したオブジェクトの内容をコピーしていないため、メモリの漏洩、複数回のプロファイルなどの問題を引き起こしやすいことに注意してください.
(2)深いコピーは、新しいオブジェクトのメンバーにメモリ領域を再開し、各オブジェクトが独自のリソースを共有しているため、コピーコンストラクタと付与演算子を明示的に提供する必要があります.
1.浅いコピーの問題
クラスFileを例にとると、まずFileタイプのオブジェクトaが作成され、Fileタイプのオブジェクトbはaの浅いコピーによって得られる.
浅いコピーの場合、aのポインタタイプオブジェクトに対して_fp,bはa中_のみcopyしたfpポインタが指すオブジェクトのアドレスは、
では、浅いコピー後、a,bオブジェクトの_fpポインタは同じメモリを指しています.
これはクラスが析出する際に複数回析出されるという問題が起こりやすい.
2.解決方法
ポインタタイプを含むクラスでは,(1)の問題を回避するために,進数コピー構造,付与構造などを用いることができる.(RAIIは動作をコピーしていません)
次の例では、コピーと付与によって構築されたマクロを定義し、privateで宣言します.
では、クラスオブジェクトをコピーまたは付与構造しようとすると、privateのconstructorがエラーを発生させます.
(1)浅いコピーは「ビットコピー」方式を採用する.int、floatなどの基礎タイプについては、直接copyすることができます.
ただし、ポインタタイプでは、copyの場合、浅いコピーはポインタが指すアドレスのみをcopyし、そのアドレスを作成したオブジェクトの内容をコピーしていないため、メモリの漏洩、複数回のプロファイルなどの問題を引き起こしやすいことに注意してください.
(2)深いコピーは、新しいオブジェクトのメンバーにメモリ領域を再開し、各オブジェクトが独自のリソースを共有しているため、コピーコンストラクタと付与演算子を明示的に提供する必要があります.
1.浅いコピーの問題
クラスFileを例にとると、まずFileタイプのオブジェクトaが作成され、Fileタイプのオブジェクトbはaの浅いコピーによって得られる.
浅いコピーの場合、aのポインタタイプオブジェクトに対して_fp,bはa中_のみcopyしたfpポインタが指すオブジェクトのアドレスは、
では、浅いコピー後、a,bオブジェクトの_fpポインタは同じメモリを指しています.
これはクラスが析出する際に複数回析出されるという問題が起こりやすい.
#include
using namespace std;
class File
{
public:
explicit File(const char *file_name) {};
~File() {};
void addr_fp() {
cout << _fp << endl;
}
private:
FILE *_fp;
};
int main()
{
File a("./a.txt");
cout << "a._fp addr" << endl;
a.addr_fp();
File b = a;
cout << "b._fp addr" << endl;
b.addr_fp();
return 0;
}
/** output
a._fp addr
0x7ffee45649d8
b._fp addr
0x7ffee45649d8
**/
2.解決方法
ポインタタイプを含むクラスでは,(1)の問題を回避するために,進数コピー構造,付与構造などを用いることができる.(RAIIは動作をコピーしていません)
次の例では、コピーと付与によって構築されたマクロを定義し、privateで宣言します.
では、クラスオブジェクトをコピーまたは付与構造しようとすると、privateのconstructorがエラーを発生させます.
#include
using namespace std;
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&);\
TypeName& operator=(const TypeName&)
class File
{
public:
explicit File(const char *file_name) {};
~File() {};
void addr_fp() {
cout << _fp << endl;
}
private:
FILE *_fp;
DISALLOW_COPY_AND_ASSIGN(File);
};
int main()
{
File a("./a.txt");
cout << "a._fp addr" << endl;
a.addr_fp();
File b = a;
cout << "b._fp addr" << endl;
b.addr_fp();
return 0;
}
/** output
deep_shallow_copy.cpp:30:11: error: calling a private constructor of class 'File'
File b = a;
^
deep_shallow_copy.cpp:21:27: note: declared private here
DISALLOW_COPY_AND_ASSIGN(File);
^
1 error generated.
**/