- 2012-04-28 (土) 19:16
- C++
HPや前ブログで書いている記事ですが、情報の一元化のためこちらに転載しておきます。
クラスのメモリコピーにはバグの危険が潜んでいるのですが、何故それが危険なのかを知らない人が意外と多いようなので簡単に解説したいと思います。
クラスのメモリコピーが危険とは書きましたが、全部が全部ダメというわけではありません。内部でヒープ管理を行っているクラスの場合に限って、メモリコピーがバグの原因になることがあります。
例えば、コンストラクタでヒープ取得、デストラクタでヒープ解放するCHogeクラスがあったとします。
Hoge.h
class CHoge { public: CHoge(); CHoge(const CHoge& obj); ~CHoge(); private: char* m_pHoge; }
Hoge.cpp
// コンストラクタ CHoge::CHoge() { m_pHoge = new char[10]; } // コピーコンストラクタ CHoge::CHoge(const CHoge& obj) { m_pHoge = new char[10]; memcpy(m_pHoge, obj.m_pHoge, (sizeof(char) * 10)); } // デストラクタ CHoge::~CHoge() { delete[] m_pHoge; }
さて、このクラスをコピーしてみましょう。
void func() { CHoge hoge1 = CHoge(); CHoge hoge2; //==== メモリコピー ====// memcpy(&hoge2, &hoge1, sizeof(CHoge )); // (a)これはNG /*~~ いろいろな処理 ~~*/ //==== コピーコンストラクタ ====// hoge2 = hoge1; // (b)こっちはOK /*~~ いろいろな処理 ~~*/ return; }
メモリコピー
メモリコピー部分(コメント(a)部分)から見ていきましょう。
インスタンスの存在するメモリ領域が丸々コピーされるため、m_pHogeに格納されるヒープのアドレスはhoge1とhoge2で全く同じものとなります。ということは、どちらか一方のデストラクタが呼び出されてヒープが解放されると、もう一方のm_pHogeの指すヒープ領域も解放された状態になるわけですね。
そんな状態でm_pHogeにアクセスしようとすると当然アクセスエラーが起こってしまいます。
コピーコンストラクタ
次にコピーコンストラクタ部分(コメント(b)部分)を見てみます。
こちらはコピーコンストラクタによるインスタンスのコピーです。
コピーコンストラクタ内でヒープ領域を取り直していますので、hoge2のデストラクタが呼び出されてもhoge1のヒープ領域が解放されることはありません。
まとめ
クラスのメモリコピーは、そのクラスがどのような振る舞いをみせるのかをしっかりと把握したうえで使用するようにしましょう。特に、上記のように内部でヒープを抱えているクラスには注意が必要です。
よく分からないという方は、”クラスをコピーしたい場合はメモリコピーをしない”と覚えておけば、とりあえずバグの心配はいりません。
当然ながら、構造体にCHoge型のメンバが存在する場合に構造体間でのメモリコピーすることもNGですので気を付けてください。
関連があると思われる記事:
- [Java] 「ASCIIコード⇒文字列」変換
- [WPF] Imageに画像が表示されない、そんなときは・・・
- [Android] Handler内部クラス実装時の注意点
- [Java] 現在日時の取得
- [Java] 乱数
- Newer: [Android] マルチスレッド(その1)
- Older: [Android] Googleマップを表示してみる
Comments:0
Trackbacks:0
- Trackback URL for this entry
- http://gacken.com/wp/program/cpp/848/trackback/
- Listed below are links to weblogs that reference
- [C++] クラスのメモリコピーにはご用心 from ミライニトドケ