おはようございます。
先日、友人と嵐山(京都)で花見をしようとしたところ、
強く吹き荒れる風に花見どころではなくなってしまい
結局は喫茶店で4時間ほど喋っていただけの本日の当番、プログラマーのS.Kです。
ろくに花見も出来ないままで室内に逃げ込んだので、
特にブログに書くネタが無くなってしまいました・・・。
※悪天候になる事は分かっていたので代替案を考えておくべきでした。
仕方が無いので今回はプログラマーらしく
プログラムの小ネタを書いていきます。
今回の小ネタはスマートポインタについてのお話です。
スマートポインタとはガベージコレクションの一種で
C++のように手動でメモリ管理が必要な環境でも
確保したメモリを自動的に解放してくれる便利な技術です。
例えばC++で下記のような処理を行った場合、
メモリリークが発生してしまいます。
void Hoge(void)
{
int* p = new int;
}
上記の場合は『delete p』を呼び出して
newで確保したメモリを解放してやる必要がありました。
しかしスマートポインタを使った場合は
記述を少し変更するだけでメモリの解放を自動的に行ってくれます。
※smart_ptrの実装は後述します。
void Hoge(void)
{
smart_ptr<int> p = new int;
}
元の処理との違いは『int*』を『smart_ptr<int>』に変更しているだけです。
たったこれだけの変更でメモリを自動的に解放するようになります。
何故これだけで自動的にメモリを解放してくれるようになるのか?
それはsmart_ptrの実装が次のようになっているからです。
template<class T>
class smart_ptr
{
public:
smart_ptr(void)
: _this(NULL)
{}
smart_ptr(T* p)
: _this(p)
{}
~smart_ptr(void)
{
if( _this ){ delete _this; _this = NULL; }
}
public:
operator T*(void) { return _this; }
operator const T*(void) const { return _this; }
private:
T* _this;
};
実行してくれる処理は凄く便利なスマートポインタですが、
基本的な実装は単純で簡単な内容になっています。
こんな簡単で便利なスマートポインタですが、
便利なものには裏がある!という訳でいくつかの問題も抱えています。
例えば下記のような場合に問題が発生します。
void Hoge(void)
{
//メモリリーク
{
smart_ptr<int> p = new int;
p = new int;
}
//メモリの多重解放
{
smart_ptr<int> p1;
{
smart_ptr<int> p2 = new int;
p1 = p2;
}
}
}
このようにコピー等が問題を起こすことが考えられます。
一応、上記の問題に関しては対処方法として
・メモリリーク
代入演算子をオーバーライドして、
既にポインタに値が入っている場合は解放してから代入する。
・メモリの多重解放
参照カウンタを持たせてコピー、解放時にカウンタの増減を行っておく。
解放時は参照カウンタが0の場合のみメモリを解放させる。
といった対処方法を取ることが出来ますが、
スマートポインタをグローバル変数として定義した場合や
スマートポインタの値を普通のポインタにコピーした場合など、
クラス側では制御しきれない不具合の発生も考えられるので、
使用する際には一定のルールを決めておく事を推薦します。
今回は最低限の機能を持ったスマートポインタを紹介しましたが、
STLやBoost等にもスマートポインタの機能は入っているので、
気になった方は調べてみてください。
最近のコメント