如何在python脚本中使用Pybind11修改/访问C++指针

How to modify/access a C++ pointer using Pybind11 in a python script?

本文关键字:修改 Pybind11 访问 指针 C++ python 脚本      更新时间:2023-10-16

我们正尝试将Python作为脚本语言嵌入到使用C++构建的游戏引擎中。该问题摘要如下:

在 python 中调用返回指针的 C++ 函数会导致空对象。我们想从这个指针直接调用/修改函数/变量。

游戏对象是在调用 Python Start() 行为时传递的C++类。但是,在此游戏对象上调用任何方法(返回指针(都会导致空引用。

我们如何将 C++ 函数绑定到 python 模块,以便它返回一个有效的指针(由 C++ 和 python 共享(?

我们在绑定时尝试了各种退货政策类型,但似乎都不起作用。例如:return_value_policy::referencereturn_value_policy::reference_internal

C++函数定义
MusicComponent* GetMusicComponent() 
{
    assert(HasComponent<MusicComponent>() && "Does not have component.");
    auto ptr(componentArray[GetComponentTypeID<MusicComponent>()]);
    return dynamic_cast<MusicComponent*>(ptr);
}
Python 绑定实现
//Unique pointer because the destructor and constructor are private 
py::class_<Gameobject , std::unique_ptr<Gameobject, py::nodelete>>gameobject (IridiumModule, "GameObject");

gameobject.def("GetMusicComponent", &Gameobject::GetMusicComponent, py::return_value_policy::automatic_reference);
蟒蛇脚本
class PyScriptComponent():
    def Start(gameObject):       
       comp = gameObject.GetMusicComponent()
       print(comp) #prints none
       comp.PlayMusic() #error: null reference
公开音乐组件
PYBIND11_MODULE(IridiumPython, IridiumModule) 
{
    py::class_<MusicComponent>musicComponent (IridiumModule, "MusicComponent" , baseComponent);
    baseComponent.def(py::init<Gameobject*>());
    musicComponent.def("PlayMusic", &MusicComponent::PlayMusic);
}
在引擎中调用 python 函数
pyObject.attr("Start")(GetGameobject());

思考这个问题的另一种方式可能是使用 PYBIND11_EMBEDDED_MODULE ,而不是在 Python 和 C++ 之间共享指针。

https://pybind11.readthedocs.io/en/stable/advanced/embedding.html#adding-embedded-modules

这样,该类将被"嵌入"到内置的python模块中,您可以拥有一个由Python和C++共享的类,因此可以由其中任何一个进行修改。

但是,在这种情况下,我希望return_value_policy::reference为您工作。有可能因为它被包装在一个std::unique_ptr中,资源在C++在 Python 中使用之前被清理,这就是你得到一个空引用的原因。

也许GetMusicComponent应该返回一个unique_ptr而不是一个原始指针?