在pybind11中引用C++分配的对象

问题描述:

我想创建一个pybind11的python绑定,它引用一个C++实例的内存在C++端处理。下面是一些示例代码:在pybind11中引用C++分配的对象

import <pybind11/pybind11> 

struct Dog { 
    void bark() { printf("Bark!\n"); } 
}; 

int main() 
{ 
    auto dog = new Dog; 
    Py_Initialize(); 
    initexample(); // Initialize the example python module for import 

    // TBD - Add binding between dog and example.dog . 

    PyRun_StringFlags("import example\n" 
        "\n" 
        "example.dog.bark()\n" // Access the C++ allocated object dog. 
        , Py_file_input, main_dict, main_dict, NULL); 
    Py_Finalize(); 
} 

我卡在如何创建蟒蛇example.dog之间的联系和C++ dog变量。

我不能使用py:class_<Dog>.def(py::init<>()),因为这将分配一个新的Dog实例,这不是我想要的。

我找到了自己的问题的答案。诀窍是以下两个概念的组合:

  • 创建一个独立的函数,返回单例。
  • 创建绑定到单例类没有绑定一个构造函数。

下面的例子说明了该技术:

#include <Python.h> 
#include <pybind11/pybind11.h> 

namespace py = pybind11; 
using namespace pybind11::literals; 

// Singleton to wrap 
struct Singleton 
{ 
    Singleton() : x(0) {} 

    int exchange(int n) // set x and return the old value 
    { 
    std::swap(n, x); 
    return n; 
    } 

    // Singleton reference 
    static Singleton& instance() 
    { 
    static Singleton just_one; 
    return just_one; 
    } 

    int x; 
}; 

PYBIND11_PLUGIN(example) { 
    py::module m("example", "pybind11 example plugin"); 

    // Use this function to get access to the singleton 
    m.def("get_instance", 
      &Singleton::instance, 
      py::return_value_policy::reference, 
      "Get reference to the singleton"); 

    // Declare the singleton methods 
    py::class_<Singleton>(m, "Singleton") 
     // No init! 
     .def("exchange", 
      &Singleton::exchange, 
      "n"_a, 
      "Exchange and return the current value" 
      ) 
     ; 

    return m.ptr(); 
} 

int main(int argc, char **argv) 
{ 
    Py_Initialize(); 

    PyObject* main_module = PyImport_AddModule("__main__"); 
    PyObject* main_dict = PyModule_GetDict(main_module); 

    initexample(); 

    // Call singleton from c++ 
    Singleton::instance().exchange(999); 

    // Populate the example class with two static pointers to our instance. 
    if (PyRun_StringFlags("import example\n" 
         "\n" 
         "example.s1 = example.get_instance()\n" 
         "example.s2 = example.get_instance()\n", 
         Py_file_input, main_dict, main_dict, NULL) == nullptr) 
     PyErr_Print(); 

    // Test referencing the singleton references 
    if (PyRun_StringFlags("from example import *\n" 
         "\n" 
         "for i in range(3):\n" 
         " print s1.exchange(i*2+1)\n" 
         " print s2.exchange(i*2+2)\n" 
         "print dir(s1)\n" 
         "print help(s1.exchange)\n" 
         , 
         Py_file_input, main_dict, main_dict, NULL) == nullptr) 
     PyErr_Print(); 

    Py_Finalize(); 

    exit(0); 
}