2011年6月14日火曜日

スマートポインタの問題点

C++/CLI という仕様ではガベッジコレクションにより、ポインタ解放の義務がありません。これは、使ったことのある人ならわかると思いますが非常に便利な機能で、必要に応じていくらでもインスタンスを構築し、不要になったらそのまま放置しとけば勝手に裏で解放してくれます。まあ、これはこれで別の問題があるのですが。
標準 C++ にも似たようなことを実現するライブラリがあります。スマートポインタと呼ばれるもので、次期仕様である C++0x に取り込まれる予定で、現在でも boost ライブラリを導入することによってすぐにでも使うことのできる機能です。
void foo()
{
    boost::shared_ptr<Hoge> ptr0( new Hoge );
    // ポインタと同じように使うことができる
    ptr->Func();
    // コピーすると参照カウンタが +1 される
    boost::shared_ptr<Hoge> ptr1 = ptr0;
    // ptr0, ptr1 の両方のインスタンスがなくなると、
    // 自動的に delete される
}

最初は、ポインタをすべてこのような形で使用するよう心がければ、ガベッジコレクションなどなくても C++/CLI と同様にポインタ管理しなくてもよくなる、と考えていました。作られたインスタンスにアクセスするためには、元のスマートポインタまたはそのコピーを使用する必要があるわけですから、不意に解放されたポインタにアクセスしてしまう心配もありません。

しかし、やはりというか、問題がありました。このスマートポインタまたはそのコピーを使用せずにインスタンスにアクセスするケースがあります。それは、そのクラス自身のメンバ関数です。メンバ関数は this  というポインタを使用することによってスマートポインタを経由せずに、いつでも自由にそのインスタンスにアクセスすることができてしまいます。メンバ関数が実行されているということは、そのインスタンスが存在するということですから一見問題ないように思いますが、その this を外部の関数等に渡すことを考えるとどうでしょう?その関数でポインタを保存しておいて、別の機会にアクセスされるとしたら、そのポインタが有効かどうかが別の方法によって知らされない限り不正アクセスが発生する危険性があります。

クラス Hoge に weak_ptr をメンバとして持たせておいて、クラス Hoge を構築する度にそのスマートポインタから weak_ptr を作成しセットする、というのも考えましたがどうにも面倒です。そもそも、クラスを構築するために必ず new で確保しスマートポインタに入れなければならないということを義務づけるのも、あまり好ましくありません。

これらのことから、このスマートポインタだけではガベッジコレクションの代わりはできそうにないな、と結論しました。そして、別の手段を模索することになります。...続く

0 件のコメント:

コメントを投稿