使用boost-python将python变量设置为C ++对象指针 [英] Set a python variable to a C++ object pointer with boost-python

查看:167
本文介绍了使用boost-python将python变量设置为C ++对象指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从C ++设置一个Python变量,以便C ++程序可以创建一个对象Game* game = new Game();,以便Python代码能够引用该实例(以及调用函数等).我该如何实现?

I want to set a Python variable from C++ so that the C++ program can create an object Game* game = new Game(); in order for the Python code to be able to reference this instance (and call functions, etc). How can I achieve this?

我觉得我对Python或Boost-Python的工作方式有一些核心误解.

I feel like I have some core misunderstanding of the way Python or Boost-Python works.

main_module.attr("game") = game在try catch语句中,并且错误(使用PyErr_Fetch)是找不到C ++类型的To_python(按值)转换器:类Game".

The line main_module.attr("game") = game is in a try catch statement, and the error (using PyErr_Fetch) is "No to_python (by-value) converter found for C++ type: class Game".

例如

class_<Game>("Game")
        .def("add", &Game::add)
;

object main_module = import("__main__");
Game* game = new Game();
main_module.attr("game") = game; //This does not work

从Python:

import testmodule

testmodule.game.foo(7)

推荐答案

在处理语言绑定时,通常必须在细节上花哨.默认情况下,当C ++对象越过语言边界时,Boost.Python将创建一个副本,因为这是防止悬挂引用的最安全的方法.如果不应该制作副本,则需要明确说明C ++对象的所有权:

When dealing with language bindings, one often has to be pedantic in the details. By default, when a C++ object transgresses the language boundary, Boost.Python will create a copy, as this is the safest course of action to prevent dangling references. If a copy should not be made, then one needs to be explicit as to the ownership of the C++ object:

  • 要在保持对C ++所有权的同时将对C ++对象的引用传递给Python,请使用 manage_new_object ResultConverterGenerator ,允许将所有权转让给Python.一旦Python对象的生命周期结束,C ++代码就不应尝试访问指针.
  • 对于共享所有权,需要使用 HeldType .
  • To pass a reference to a C++ object to Python while maintaining ownership in C++, use boost::python::ptr() or boost::ref(). The C++ code should guarantee that the C++ object's lifetime is at least as long as the Python object. When using ptr(), if the pointer is null, then the resulting Python object will be None.
  • To transfer ownership of a C++ object to Python, one can apply the manage_new_object ResultConverterGenerator, allowing ownership to be transferred to Python. C++ code should not attempt to access the pointer once the Python object's lifetime ends.
  • For shared ownership, one would need to expose the class with a HeldType of a smart pointer supporting shared semantics, such as boost::shared_ptr.

一旦创建了Python对象,就需要将其插入Python名称空间以使其通常可以访问:

Once the Python object has been created, it would need to be inserted into a Python namespace to be generally accessible:

  • 在模块定义中,使用 boost::python::scope 以获得当前范围的句柄.例如,以下将x插入example模块:

BOOST_PYTHON_MODULE(example)
{
  boost::python::scope().attr("x") = ...; // example.x
}

  • 要插入__main__模块,可以导入__main__.例如,以下将x插入__main__模块:

  • To insert into the __main__ module, one can import __main__. For example, the following would insert x into the __main__ module:

    boost::python::import("__main__").attr("x") = ...;
    

  • 这里是一个示例演示如何从C ++直接构造Python对象,拥有C ++对象对Python的所有权,并构造一个引用C ++对象的Python对象:

    Here is an example demonstrating how to directly construct the Python object from C++, transfer ownership of a C++ object to Python, and construct a Python object that references a C++ object:

    #include <iostream>
    #include <boost/python.hpp>
    
    // Mockup model.
    struct spam
    {
      spam(int id)
        : id_(id)
      {
        std::cout << "spam(" << id_ << "): "  << this << std::endl;
      }
    
      ~spam()
      {
        std::cout << "~spam(" << id_ << "): " << this << std::endl;
      }
    
      // Explicitly disable copying.
      spam(const spam&) = delete;
      spam& operator=(const spam&) = delete;
    
      int id_;
    };
    
    /// @brief Transfer ownership to a Python object.  If the transfer fails,
    ///        then object will be destroyed and an exception is thrown.
    template <typename T>
    boost::python::object transfer_to_python(T* t)
    {
      // Transfer ownership to a smart pointer, allowing for proper cleanup
      // incase Boost.Python throws.
      std::unique_ptr<T> ptr(t);
    
      // Use the manage_new_object generator to transfer ownership to Python.
      namespace python = boost::python;
      typename python::manage_new_object::apply<T*>::type converter;
    
      // Transfer ownership to the Python handler and release ownership
      // from C++.
      python::handle<> handle(converter(*ptr));
      ptr.release();
    
      return python::object(handle);
    }
    
    namespace {
    spam* global_spam;
    } // namespace
    
    BOOST_PYTHON_MODULE(example)
    {
      namespace python = boost::python;
      // Expose spam.
      auto py_spam_type = python::class_<spam, boost::noncopyable>(
          "Spam", python::init<int>())
        .def_readonly("id", &spam::id_)
        ;
    
      // Directly create an instance of Python Spam and insert it into this
      // module's namespace.
      python::scope().attr("spam1") = py_spam_type(1);
    
      // Construct of an instance of Python Spam from C++ spam, transfering
      // ownership to Python.  The Python Spam instance will be inserted into
      // this module's namespace.
      python::scope().attr("spam2") = transfer_to_python(new spam(2));
    
      // Construct an instance of Python Spam from C++, but retain ownership of
      // spam in C++.  The Python Spam instance will be inserted into the
      // __main__ scope.
      global_spam = new spam(3);
      python::import("__main__").attr("spam3") = python::ptr(global_spam);
    }
    

    互动用法:

    >>> import example
    spam(1): 0x1884d40
    spam(2): 0x1831750
    spam(3): 0x183bd00
    >>> assert(1 == example.spam1.id)
    >>> assert(2 == example.spam2.id)
    >>> assert(3 == spam3.id)
    ~spam(1): 0x1884d40
    ~spam(2): 0x1831750
    

    在示例用法中,请注意Python如何在退出时不破坏spam(3),因为它没有被授予基础对象的所有权.

    In the example usage, note how Python did not destroy spam(3) upon exit, as it was not granted ownership of the underlying object.

    这篇关于使用boost-python将python变量设置为C ++对象指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆