6

Boost.Python と C++ で遊んでいるときに、クラス自体とboost::shared_ptr<>バージョンを使用してバインドされたクラスを作成することがあります。これは多くの理由で非常に便利で、多くの場所で使用できます。ただし、 Python で生成され、C++ 静的変数に記録された値にboost::pythona を返す場合、このメカニズムは確実に機能しないようです。boost::shared_ptr<>

通常、boost::shared_ptr<>returned には、これを処理する特別なデリータが保持されると予想されますが、そうではないようです。何が起こるように見えるのは、返さboost::shared_ptrれたものは、Python で生成された値へのポインタをラップするだけであり、削除に関する特別な考慮事項はありません。これにより、二重削除 (Python インタープリター自体からの削除と C++ 静的からの削除) による一貫したクラッシュが発生するか、少なくともそのように見えます。

以下のコードを使用してこの動作を再現するには、test.cc以下のようなファイルを作成し、次のスクリプトでテストします。

#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>

struct A {
  std::string _a;
  A(std::string a): _a(a) {}
  std::string str() { return _a; }
};

static boost::shared_ptr<A> holder(new A("foo"));

static void set_holder(boost::shared_ptr<A> a_ptr) {
  holder = a_ptr;
}

static boost::shared_ptr<A> get_holder() {
  return holder;
}

BOOST_PYTHON_MODULE(test)
{
  using namespace boost::python;

  class_<A, boost::shared_ptr<A> >("A", init<std::string>())
    .def("__str__", &A::str)
    ;

  def("set_holder", &set_holder);
  def("get_holder", &get_holder);
}

次の Python テスト プログラムを使用します。

import test
print(str(test.get_holder()))
test.set_holder(test.A('bar'))
print(str(test.get_holder()))

Linux (ubuntu 12.10、Python 2.7 および Boost 1.50) でg++ -I/usr/include/python2.7 -shared -fpic test.cc -lboost_python -lpython2.7 -o test.so上記のプログラム ( ) をコンパイル ( ) して実行すると、次のスタック トレースが生成されます。python test.py

#0  0x000000000048aae8 in ?? ()
#1  0x00007fa44f85f589 in boost::python::converter::shared_ptr_deleter::operator()(void const*) () from /usr/lib/libboost_python-py27.so.1.50.0
#2  0x00007fa44fa97cf9 in boost::detail::sp_counted_impl_pd<void*, boost::python::converter::shared_ptr_deleter>::dispose() ()
   from /remote/filer.gx/home.active/aanjos/test.so
#3  0x00007fa44fa93f9c in boost::detail::sp_counted_base::release() ()
   from /remote/filer.gx/home.active/aanjos/test.so
#4  0x00007fa44fa9402b in boost::detail::shared_count::~shared_count() ()
   from /remote/filer.gx/home.active/aanjos/test.so
#5  0x00007fa44fa94404 in boost::shared_ptr<A>::~shared_ptr() ()
   from /remote/filer.gx/home.active/aanjos/test.so
#6  0x00007fa450337901 in __run_exit_handlers (status=0, 
    listp=0x7fa4506b46a8 <__exit_funcs>, run_list_atexit=true) at exit.c:78
#7  0x00007fa450337985 in __GI_exit (status=<optimized out>) at exit.c:100
#8  0x00007fa45031d774 in __libc_start_main (main=0x44b769 <main>, argc=2, 
    ubp_av=0x7fffaa28e2a8, init=<optimized out>, fini=<optimized out>, 
    rtld_fini=<optimized out>, stack_end=0x7fffaa28e298) at libc-start.c:258
#9  0x00000000004ce6dd in _start ()

これは、静的デストラクタで二重削除が発生したことを示します。この動作は、異なるプラットフォーム間で一貫しているようです。

質問: から返された値をコピーせずに、説明されている動作を実現することは可能boost::pythonですか? 上記のおもちゃの例では、それは簡単ですが、私の実際の問題では、のディープコピーはA実用的ではありません。

4

1 に答える 1