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