python 指针 对象_使用boost-python将python变量设置为C ++对象指针

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?

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

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".

E.g.

class_("Game")

.def("add", &Game::add)

;

object main_module = import("__main__");

Game* game = new Game();

main_module.attr("game") = game; //This does not work

From Python:

import testmodule

testmodule.game.foo(7)

解决方案

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:

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.

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

From within the module definition, use boost::python::scope to obtain a handle to the current scope. For example, the following would insert x into the example module:

BOOST_PYTHON_MODULE(example)

{

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

}

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") = ...;

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

#include

// 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

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 ptr(t);

// Use the manage_new_object generator to transfer ownership to Python.

namespace python = boost::python;

typename python::manage_new_object::apply::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", python::init())

.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);

}

Interactive usage:

>>> 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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值