Boost logo

Boost Users :

Subject: [Boost-users] Boost.Python shared_ptr bug?
From: Christoff Kok (christoff.kok_at_[hidden])
Date: 2014-11-10 08:21:42


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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net