[C++] std::auto_ptrと不完全クラスの問題点

2011 年 8 月 16 日 Categories: C++ | Tags:


#include <memory>

class Incomplete; // 前方宣言

class Sample {
	std::auto_ptr<incomplete> autoPtr;

	Sample();
	~Sample();
};

Sample::Sample() : autoPtr(new Incomplete){}

// Sampleのデストラクタを先に定義
Sample::~Sample(){}

class Incomplete {
	// 宣言(定義)
};

前方宣言をしただけのような不完全クラスのインスタンスをstd::auto_ptrで保持しようとしたとき、上のような場合にはインスタンスが解放されず、メモリリークが生じてしまう。

ポイントは、Incompleteクラスの実際の宣言の位置。Sampleクラスのデストラクタより後になってしまうと、そのデストラクタはIncompleteクラスの解放の仕方がわからず、std::auto_ptrが保持するインスタンスはそのままになってしまう(コンパイラによっては警告が出ない)。

これを避けるには、Sampleクラスのデストラクタを常に最後に定義するようにすればいいのだが、うっかりミスが起きやすく、またこの問題点を知らない人はメモリリークを放置してしまいかねない。さらにVisual C++ 2010のコンパイラでは、対策を施してもなぜか警告が出てしまう。

そこで、素直にboost::scoped_ptrやboost::shared_ptrを使う。これらは内部で動的削除子という技法を用いているため、上記のようなことを一切気にする必要がない。

Pimplイディオムを使う際などに起きやすい問題なので注意しよう。