在使用 Boost.Python 和 C++ 时,有时我们会创建使用类本身和boost::shared_ptr<>
版本绑定的类。由于许多原因,这非常方便,并且可以在很多地方使用。但是boost::python
,当将 a 返回boost::shared_ptr<>
到在 Python 中生成并记录在 C++ 静态变量上的值时,该机制似乎无法可靠地工作。
通常情况下,我希望返回boost::shared_ptr<>
的人持有一个特殊的删除器来处理这个问题,但情况似乎并非如此。似乎发生的情况是,返回的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
是不切实际的。