如何将基本类型的shared_ptr导出到python

How to export a shared_ptr of a fundamental type to python

本文关键字:ptr python shared 类型      更新时间:2023-10-16

我试图在python中使用基本类型的shared_ptr(例如int或double),但我不知道如何将其导出到python:

我有以下类:

class Holder
{
public:
    Holder(int v) : value(new int(v)) {};
    boost::shared_ptr<int> value;
};

类以这种方式被导出:

class_<Holder>("Holder", init<int>())
    .def_readwrite("value", &Holder::value);

在python代码中,我试图使用已经存在的实例设置"holder instance .value"。

h1 = mk.Holder(10)
h2 = mk.Holder(20)
h1.value = h2.value

发生以下情况:

TypeError: No to_python (by-value) converter found for C++ type: class boost::shared_ptr<int>

我的问题是:我如何将boost::shared_ptr<int>导出到python?

可以使用boost::python::class_boost::shared_ptr<int>导出到Python,方法与其他类型相同:

boost::python::class_<boost::shared_ptr<int> >(...);

但是,在公开shared_ptr时要小心引入的语义。例如,将一个Holder.value赋值给另一个Holder.value只是调用boost::shared_ptr<int>的赋值操作符,并且Holder.increment()操作value所指向的int,而不是让value指向新的int:

h1 = Holder(10)
h2 = Holder(20)
h1.value = h2.value # h1.value and h2.value point to the same int.
h1.increment() # Change observed in h2.value.  The semantics may be unexpected
               # by Python developers.

下面是一个基于原始代码暴露boost::shared_ptr<int>的完整示例:

#include <sstream>
#include <string>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
class Holder
{
public:
  Holder(int v)
    : value(new int(v))
  {};
  boost::shared_ptr<int> value;
};
std::string holder_value_str(const boost::shared_ptr<int>& value)
{
  std::stringstream stream;
  stream << value.get() << " contains " << *value;
  return stream.str();
}
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  {
    python::scope holder = python::class_<Holder>(
        "Holder", python::init<int>())
      .def_readwrite("value", &Holder::value)
      ;
    // Holder.Value
    python::class_<boost::shared_ptr<int> >("Value", python::no_init)
      .def("__str__", &holder_value_str)
      ;
  }
}
互动用法:

>>> import example
>>> h1 = example.Holder(10)
>>> h2 = example.Holder(20)
>>> print h1.value
0x25f4bd0 contains 10
>>> print h2.value
0x253f220 contains 20
>>> h1.value = h2.value
>>> print h1.value
0x253f220 contains 20

或者,如果认为shared_ptr只不过是一个c++内存管理代理,那么在Python中将Holder.value公开为int可能是合理的,即使Holder::valueboost::shared_ptr<int>。这将为Python开发人员提供预期的语义并允许诸如h1.value = h2.value + 5之类的语句。下面是一个使用辅助函数将Holder::value转换为int,而不是暴露boost::shared_ptr<int>类型的示例:

#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
class Holder
{
public:
  Holder(int v)
    : value(new int(v))
  {};
  boost::shared_ptr<int> value;
};
/// @brief Auxiliary function used to get Holder.value.
int get_holder_value(const Holder& self)
{
  return *(self.value);
}
/// @brief Auxiliary function used to set Holder.value.
void set_holder_value(Holder& self, int value)
{
  *(self.value) = value;
}
BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::scope holder = python::class_<Holder>(
      "Holder", python::init<int>())
    .add_property("value",
      python::make_function(&get_holder_value),
      python::make_function(&set_holder_value))
    ;
}
互动用法:

>>> import example
>>> h1 = example.Holder(10)
>>> h2 = example.Holder(20)
>>> assert(h1.value == 10)
>>> assert(h2.value == 20)
>>> h1.value = h2.value
>>> assert(h1.value == 20)
>>> h1.value += 22
>>> assert(h1.value == 42)
>>> assert(h2.value == 20)

你需要吗?Python有自己的引用计数机理,用它可能会更简单。(但是很多取决于c++端发生了什么)

否则:您可能需要定义一个Python对象来包含共享指针。这是相对简单的:只需定义如下内容:

struct PythonWrapper
{
    PyObject_HEAD
    boost::shared_ptr<int> value;
    //  Constructors and destructors can go here, to manage
    //  value.
};

并像对待其他对象一样声明和管理它;只是当任何类型的对象都是时,请确保执行new创建(并且必须在您提供给的函数中创建)Python中,如果tp_new字段中的函数中没有其他内容,在tp_dealloc字段中的函数中添加一个delete