boost.python return_internal_reference策略

时间:2016-08-09 16:22:30

标签: c++ boost-python

对于以下两个类:

class A {
};

class B {
public:

    B()
    : a_(std::make_shared<A>())
    {} 

    std::shared_ptr<A> a_;
};

有一个简单的boost.python包装

A& get_a(const B& b) {
    return *b.a_; // intentionally, no check here; doesn't matter for the example
}

boost::python::class_<A, std::shared_ptr<A>>("A");

boost::python::class_<B>("B")
   .def("get_a", &get_a, boost::python::return_internal_reference<>());

在Python中有简单的成员检索:

import ext
b = ext.B()
a1 = b.get_a()
a2 = b.get_a()

我期待的是

id(a1) == id(a2)

不适用于上述情况,这意味着创建了两个不同的PyObject作为A包装器。 为什么? return_internal_reference策略是否阻止创建多个临时对象?

如果我从std::shared_ptr<A>返回get_a,则程序无法编译。

此问题与此one有相似之处。然而,在后一种情况下,存在可能无法跟踪的临时物体。另一方面,成员变量的包装器存储在python变量中。

1 个答案:

答案 0 :(得分:1)

return_internal_reference策略允许返回指针或对内部持有对象的引用,而无需Boost.Python复制引用。它并不意味着后续调用将返回相同的Python对象。

以下是使用return_internal_reference时未复制C ++对象的示例demonstrating,并且多个离散Python对象可以嵌入对同一C ++对象的引用:

#include <boost/python.hpp>
#include <cstdint> // std::uintptr_t

struct spam
{
  uintptr_t id() { return reinterpret_cast<uintptr_t>(this); }
};

struct egg {};

spam& get_spam(const egg&)
{
  static spam instance;
  return instance;
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  python::class_<spam>("Spam")
    .def("id", &spam::id)
    ;

  python::class_<egg>("Egg")
    .def("get_spam", get_spam, python::return_internal_reference<>())
    ;
}

交互式使用:

import example
egg = example.Egg()
spam1 = egg.get_spam()
spam2 = egg.get_spam()
assert(spam1.id() == spam2.id()) # reference same C++ object
assert(id(spam1) != id(spam2))   # non-identical Python objects