boost::shared_ptrで少し不思議な挙動に出会いました。

// 下のコメントアウトを外すとコンパイルが通る。
// #define BOOST_SP_NO_SP_CONVERTIBLE
 
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
 
class B {};
class B1 : public B {};
class B2 : public B {};
 
class D : public B1, public B2
{
public:
  B* get();
};
 
int main()
{
  boost::shared_ptr<D> d = boost::make_shared<D>();
  boost::shared_ptr<B> b(d, d.getB());
}

bの初期化で使用しているコンストラクタは、ポインタの値はd.getB()だけど参照カウントはdを共有するというものです。詳しい説明が今更ながらに Boost.SmartPointers を考える – 銀天随筆集の「応用的な使い方」にあります。

さて、これは特に問題ない(コンパイルエラーになるコードではない)と思うのですが、DからBへの変換が曖昧だということでエラーになってしまいました。これが遭遇した少し不思議な挙動です。

解決方法は、2つ見つけました。

1つは、上記ソースコードに書いてあるように、BOOST_SP_NO_SP_CONVERTIBLEを定義するという方法です。エラーメッセージに出力されたソースファイルboost/smart_ptr/detail/sp_convertible.hppを開いたところ、見つけました。

もう1つはboost::shared_ptr<void>を介す方法です。BOOST_SP_NO_SP_CONVERTIBLEの定義が望ましいエラーチェックまで無くしてしまうことを危惧するなら、こちらが良いと思います。

int main()
{
  boost::shared_ptr<D> d = boost::make_shared<D>();
  boost::shared_ptr<void> tmp = d;
  boost::shared_ptr<B> b(std::move(tmp), static_cast<B1*>(d.get()));
}

なお、単にアップキャストしたいだけならboost::shared_ptr<B> b = boost::static_pointer_cast<B1>(d);などとすれば大丈夫です、一応念のため。

スポンサード リンク

この記事のカテゴリ

  • ⇒ boost::shared_ptrの少し不思議な挙動