Search code examples
pythonc++boostboost-python

Pass a C++ object by reference/pointer to Python interpreter using Boost.Python


I have a C++ object and wish to pass it by reference/pointer to an embedded Python interpreter so that Python can make changes to it which are visible to both C++ and Python. I am using Boost.Python for interop.

For sake of example, here is a class Foo, its Boost.Python wrapper, and a Foo object in C++:

mymodule.h:

struct Foo
{
    int bar;

    Foo(int num): bar(num) {}
};

mymodule.cpp:

#include "mymodule.h"
#include <boost/python.hpp>

BOOST_PYTHON_MODULE(mymodule)
{
    using namespace boost::python;

    class_<Foo>("Foo", init<int>())
        .def_readwrite("bar", &Foo::bar)
    ;
}

main.cpp:

#include <iostream>
#include <boost/python.hpp>
#include "mymodule.h"

using namespace boost::python;

int main()
{
    Py_Initialize();

    object main_module = import("__main__");
    object main_namespace = main_module.attr("__dict__");
    import("mymodule");

    Foo foo(42);

    // ... somehow use Boost.Python to send reference to interpreter ... 

    object result = exec_file("myscript.py", main_namespace);

    std::cout << foo.bar << std::endl;                
}

So how do I send a reference of foo to Python so both C++ and Python can see its contents?


Solution

  • In C++, prior to running the script, add:

    main_namespace["foo"] = ptr(&foo);
    

    Now the Python environment will have a pointer to the C++ variable foo and any changes made to it by a Python script will be performed on the C++ object rather than a copy.

    If myscript.py is:

    foo.bar = 12
    

    then the output of the cout line at the end will be 12, not 42.

    Note that you may want to place foo inside the mymodule namespace to self-document its origin, i.e. mymodule.foo.bar.

    The Boost.Python documentation doesn't seem to describe this method of pass-by-pointer, but it works nonetheless.