auto_ptr の微妙な仕様(「バグ」とも言う(^^;)

C++ の std::auto_ptr に関する,ちょっとした覚書です。
# 以下の内容は VS2005 の VC++(8.0)で確認したものです。
# 他のバージョンや他処理系では動作に違いがあるかも知れません。

auto_ptr は C++ インスタンスの寿命(生成/開放)を管理するテンプレートで,
  auto_ptr<SomeClass> aPtr(new SomeClass());

のように宣言しておくと,メソッド終了時などにインスタンスを開放してくれる訳ですが,この宣言を
  auto_ptr<SomeClass> aPtr = new SomeClass();
とやってしまうと,実行時に Access Vioration で落ちてしまいます。

コンパイル時にはエラーや警告など,一切出ません。
で,理由が分からずに深く悩んだりします(^^;

仕方ないので出力されたコードを調べてみると,ポインタの代入時に auto_ptr_ref というクラスへの変換が挿入されてしまっているのが分かります。

  auto_ptr aPtr = auot_ptr_ref(new SomeClass();)

だいたいこんなイメージです(厳密にはちょっと違いますが)。

auto_ptr には T* を引数とする代入演算子がなく,auto_ptr_ref を引数として取る代入演算子が定義されているため,このような暗黙の変換が挿入されるのだと思われます。

これでうまく動くのならばOKなのですが,実際のコードはポインタの参照値がポインタとして扱われてしまっていて(SomeClass** として参照されていて),アクセスした時点でダウン,という構造になっています。

で,この auto_ptr_ref というクラス,ドキュメントにも記載されていない内部定義のようですが,どうにも実装が怪しい。

// TEMPLATE CLASS auto_ptr
template<class _Ty>
class auto_ptr;

template<class _Ty>
struct auto_ptr_ref
{ // proxy reference for auto_ptr copying
auto_ptr_ref(void *_Right)
: _Ref(_Right)
{ // construct from generic pointer to auto_ptr ptr
}

void *_Ref; // generic pointer to auto_ptr ptr
};

auto_ptr の宣言がこれに続くのですが,これを見ただけで
  • 前方参照もしていない auto_ptr を宣言しているのは何故?
  • テンプレート引数 _Ty は使用しない?(テンプレートじゃない?)
など,疑問点がふつふつ湧いてきます。

このクラス(テンプレート?)自体は,auto_ptr 同士を代入演算子で転送するときのためのものと思うのですが,実装のレベルや今回のポインタ代入の問題を見ると,どうにも失敗作としか思えません。

もう少し完成度の高い Smart Pointer が一般的に使えるようになるまでは,
  1. 初期化はコンストラクタ引数で行う
  2. auto_ptr 同士の代入などは行わない
という教訓の元で使いたい,と思うのでした(^^;

追記:
やっぱり同じ内容で悩んでいる人はいるものですね。ご苦労さまです:
http://www.velocityreviews.com/forums/t458584-autoptr-assignment-crash-with-vc-language-extensions.html



タグ:C++ STL
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバック
rank← ランキングはこちらをクリック!

×

この広告は180日以上新しい記事の投稿がないブログに表示されております。