Hi,
I found an issue when accessing a shared_ptr C++ object in Python using Boost.Python.
When I try to access an attribute of the shared_ptr object read from an C++ object, I get an error telling me that the attribute does not exist.
When I use raw pointers instead of shared_ptr, then there is no issue.
Also, when using raw pointers, accessing an item in a list of base class objects returns the object in as the derived most class. This is wanted. When I use shared_ptrs however, the derived most object is of the base class type. This is not wanted.
I am sure the Boost.Python developers should be aware of these two issues by now. If so, is there any plans to fix this? If so, when?
Below is a test showing this issue:
Raw pointers:
#include<memory>
#include<vector>
struct Vehicle{
virtual ~Vehicle(){}
int testAttribute;
};
struct Boat: public Vehicle {
virtual ~Boat(){}
int testBoatAttribute;
};
struct Garage {
std::vector<Vehicle*>& vehicleList() { return m_VehicleList; }
std::vector<Vehicle*> m_VehicleList;
};
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
BOOST_PYTHON_MODULE(garage_ext) {
using namespace boost::python;
class_<Garage>("Garage")
.def("vehicleList", &Garage::vehicleList, return_internal_reference<1>());
class_<Vehicle,Vehicle*,boost::noncopyable>("Vehicle", no_init)
.def_readwrite("testAttribute", &Vehicle::testAttribute);
class_<Boat,Boat*,bases<Vehicle>>("Boat")
.def_readwrite("testBoatAttribute", &Boat::testBoatAttribute);
implicitly_convertible<Boat*, Vehicle*>();
class_<std::vector<Vehicle*> >("stl_vector_Vehicle_ptr")
.def(vector_indexing_suite<std::vector<Vehicle*>>());
}
Shared pointers:
#include<memory>
#include<vector>
#include <boost/shared_ptr.hpp>
struct Vehicle{
virtual ~Vehicle(){}
friend bool operator==(const Vehicle& lhs, const Vehicle& rhs) { return true; }
int testAttribute;
};
struct Boat: public Vehicle {
virtual ~Boat(){}
friend bool operator==(const Boat& lhs, const Boat& rhs) { return true; }
int testBoatAttribute;
};
struct Garage {
friend bool operator==(const Garage& lhs, const Garage& rhs) { return true; }
std::vector<boost::shared_ptr<Vehicle>>& vehicleList() { return m_VehicleList; }
std::vector<boost::shared_ptr<Vehicle>> m_VehicleList;
};
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
BOOST_PYTHON_MODULE(garage_ext){
using namespace boost::python;
class_<Garage>("Garage")
.def("vehicleList", &Garage::vehicleList, return_internal_reference<1>());
class_<Vehicle,boost::shared_ptr<Vehicle>,boost::noncopyable>("Vehicle", no_init)
.def_readwrite("testAttribute", &Vehicle::testAttribute);
class_<Boat,boost::shared_ptr<Boat>, bases<Vehicle>>("Boat")
.def_readwrite("testBoatAttribute", &Boat::testBoatAttribute);
implicitly_convertible<boost::shared_ptr<Boat>, boost::shared_ptr<Vehicle>>();
class_<std::vector<boost::shared_ptr<Vehicle>> >("stl_vector_Vehicle_ptr")
.def(vector_indexing_suite<std::vector<boost::shared_ptr<Vehicle>>>());
}
Python test:
from garage_ext import *
g = Garage()
l = g.vehicleList()
newboat = Boat()
newboat.testAttribute = 3
newboat.testBoatAttribute = 5
l.append(newboat)
print(type(l[0]))
print(str(hasattr(l[0],"testAttribute")))
print(str(l[0].testAttribute))
b = l[0]
print(type(b))
print(str(b.testBoatAttribute))
print("Done.")
Raw pointer result:
<class 'garage_ext.Boat'>
True
3
<class 'garage_ext.Boat'>
5
Done.
Shared pointer result:
<class 'garage_ext.Vehicle'> // Expected it to be Boat as with Raw pointers
Traceback (most recent call last):
File "test_garage.py", line 9, in <module>
print(str(hasattr(l[0],"testAttribute"))) // Expected attribute to exist as with Raw pointers. Note: dir(l[0]) shows that it has the attribute. Accessing the attribute however throws an error.
Boost.Python.ArgumentError: Python argument types in
None.None(Vehicle)
did not match C++ signature:
None(Vehicle {lvalue})
Kind Regards,
Christoff