pybind11
pybind11 copied to clipboard
[QUESTION] How to expose pointer member with boost::python behavior
Hello! I am migrating from boost::python to pybind11 and have just faced some pointer member behavior issue:
class SomeClass
{
};
struct SomeStruct
{
public:
SomeClass* scPtr;
};
void foo( SomeStruct& str )
{
if ( str.scPtr )
*str.scPtr;
}
// pybind11 version
PYBIND11_MODULE( mod, m )
{
pybind11::class_<SomeClass>( m, "SomeClass" ).def( pybind11::init<>() );
pybind11::class_<SomeStruct>( m, "SomeStruct" ).def( pybind11::init<>() ).
def_readwrite( "scPtr", &SomeStruct::scPtr);
m.def( "foo", &foo );
}
// boost python version
BOOST_PYTHON_MODULE( mod )
{
boost::python::class_<SomeClass>( "SomeClass" );
boost::python::class_<SomeStruct>( "SomeStruct" ).
add_property( "scPtr",
boost::python::make_getter( &SomeStruct::scPtr, boost::python::return_value_policy<boost::python::reference_existing_object>() ),
boost::python::make_setter( &SomeStruct::scPtr, boost::python::return_value_policy<boost::python::reference_existing_object>() ) );
boost::python::def( "foo", &foo );
}
Python behavior
import mod
#boost version
stru = mod.SomeStruct()
stru.scPtr = mod.SomeClass()
mod.foo(stru) #works ok, but in pybind this will cause access violation (as far as scPtr will be spoiled)
#pybind version
stru = mod.SomeStruct()
sc = mod.SomeClass()
stru.scPtr = sc
mod.foo(stru) #works ok
So can I make pybind11 work as boost python?
#include <pybind11/pybind11.h>
class SomeClass {
public:
SomeClass() = default;
// Other members...
};
struct SomeStruct {
SomeClass* scPtr = nullptr;
// Other members...
};
void foo(SomeStruct& str) {
if (str.scPtr) {
// Use str.scPtr...
}
}
PYBIND11_MODULE(mod, m) {
pybind11::class_<SomeClass>(m, "SomeClass")
.def(pybind11::init<>());
pybind11::class_<SomeStruct>(m, "SomeStruct")
.def(pybind11::init<>())
.def_readwrite("scPtr", &SomeStruct::scPtr, pybind11::return_value_policy::reference_existing_object);
m.def("foo", &foo);
}
Thanks! But it seems that pybind11::return_value_policy::reference_existing_object is not present in pybind11.
If somebody will come across this issue, such way might work:
class SomeClass
{
};
struct SomeStruct
{
public:
SomeClass* scPtr;
};
void foo( SomeStruct& str )
{
if ( str.scPtr )
*str.scPtr;
}
// pybind11 version
PYBIND11_MODULE( mod, m )
{
pybind11::class_<SomeClass>( m, "SomeClass" ).def( pybind11::init<>() );
pybind11::class_<SomeStruct>( m, "SomeStruct" ).def( pybind11::init<>() ).
def_property( "scPtr",
pybind11::cpp_function( []( const SomeStruct& self ) { return self.scPtr; } ),
pybind11::cpp_function( []( SomeStruct& self, SomeClass* ptr ) { self.scPtr = ptr }, pybind11::keep_alive<0,1>() )
);
m.def( "foo", &foo );
}