提振.Python return_internal_reference策略

boost.python return_internal_reference policy

本文关键字:reference 策略 internal 提振 return Python      更新时间:2023-10-16

对于以下两个类:

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策略不阻止创建多个临时对象吗?

如果我从get_a返回std::shared_ptr<A>,程序编译失败。

这个问题和这个问题有相似之处。然而,在后一种情况下,有可能不被跟踪的临时对象。另一方面,在这里,成员变量的包装器存储在python变量中。

return_internal_reference策略允许在没有Boost的情况下返回内部保存对象的指针或引用。Python复制引用。这并不意味着后续调用将返回相同的Python对象。


下面是一个示例,说明在使用return_internal_reference时不会复制c++对象,并且多个离散的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