[C++-sig] Boost.Python C++ object reference in Python: unexpected behaviour.

Christoff Kok christoff.kok at ex-mente.co.za
Tue Jun 2 07:34:09 CEST 2015


Hi,

This looks like a bug in Boost.Python to me.

Could anyone confirm this? I provided a minimal, full working example.

I would like to make sure it is a bug before reporting it as one.

Christoff

On 28 May 2015 at 09:29, Christoff Kok <christoff.kok at ex-mente.co.za> wrote:

> Hi,
>
> I am having an issue with Boost.Python with a very simple use case.
>
> I am returning a reference to an object, and it seems that my python
> object looses its C++ object's reference at a stage for some reason.
>
> Please see my *example* below reproducing this issue.
>
> *C++ Code:*
>
> #include <iostream>
> #include <vector>
> #include <string>
> #include <cmath>
> #include <boost/python.hpp>
> #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
>
> class Car {
> public:
>     Car(std::string name) : m_name(name) {}
>
>     bool operator==(const Car &other) const {
>         return m_name == other.m_name;
>     }
>
>     std::string GetName() { return m_name; }
> private:
>     std::string m_name;
> };
>
> class Factory {
> public:
>     Factory(std::string name) : m_name(name) {}
>
>     bool operator==(const Factory &other) const {
>         return m_name == other.m_name
>             && m_car_list == other.m_car_list;
>     }
>
>     Car& create_car(std::string name)
>     {
>         m_car_list.emplace_back(Car(name));
>         return m_car_list.back();
>     }
>
>     std::string GetName() { return m_name; }
>     std::vector<Car>& GetCarList() { return m_car_list;}
> private:
>     std::string m_name;
>     std::vector<Car> m_car_list;
> };
>
> class Manufacturer {
> public:
>     Manufacturer(std::string name) : m_name(name) {}
>
>     bool operator==(const Manufacturer &other) const {
>         return m_name == other.m_name
>             && m_factory_list == other.m_factory_list;
>     }
>
>     Factory& create_factory(std::string name)
>     {
>         m_factory_list.emplace_back(Factory(name));
>         return m_factory_list.back();
>     }
>
>     std::string GetName() { return m_name; }
>     std::vector<Factory>& GetFactoryList() { return m_factory_list;}
> private:
>     std::string m_name;
>     std::vector<Factory> m_factory_list;
> };
>
> BOOST_PYTHON_MODULE(carManufacturer)
> {
>     using namespace boost::python;
>     class_<Manufacturer>("Manufacturer", init<std::string>())
>         .add_property("factory_list",
> make_function(&Manufacturer::GetFactoryList,
> return_internal_reference<1>()))
>         .add_property("name", &Manufacturer::GetName)
>         .def("create_factory", &Manufacturer::create_factory,
> return_internal_reference<>());
>     class_<Factory>("Factory", init<std::string>())
>         .add_property("car_list", make_function(&Factory::GetCarList,
> return_internal_reference<1>()))
>         .add_property("name", &Factory::GetName)
>         .def("create_car", &Factory::create_car,
> return_internal_reference<>());
>     class_<Car>("Car", init<std::string>())
>         .add_property("name", &Car::GetName);
>
>     class_<std::vector<Factory> >("FactoryList")
>         .def(vector_indexing_suite<std::vector<Factory> >());
>     class_<std::vector<Car> >("Car")
>         .def(vector_indexing_suite<std::vector<Car> >());
> }
>
>
> *Python Code:*
>
> import sys
> sys.path[:0] = [r"bin\Release"]
>
> from carManufacturer import *
>
> vw = Manufacturer("VW")
> vw_bra_factory = vw.create_factory("Brazil Factory")
> beetle = vw_bra_factory.create_car("Beetle69")
>
> if vw_bra_factory is vw.factory_list[0]:
>     print("equal.")
> else:
>     print("NOT EQUAL")
> print("## I expected them to be the same reference..?")
>
>
> print("vw_bra_factory Car List size : " +
> str(len(vw_bra_factory.car_list)))
> print("Actual Car List size         : " +
> str(len(vw.factory_list[0].car_list)))
> print("## This still works. Maybe the python objects differ, but refer to
> the same C++ object. I can live with that.")
>
> vw_sa_factory = vw.create_factory("South Africa Factory")
> print("vw_bra_factory Car List size : " +
> str(len(vw_bra_factory.car_list)))
> print("Actual Car List size         : " +
> str(len(vw.factory_list[0].car_list)))
> print("## .. what? why? brazil py object has no cars now? I don't get it.
> I can't have any of that.")
>
> print("## What will happen if I create another car in the brazil factory?")
> combi = vw_bra_factory.create_car("Hippie van")
> print("vw_bra_factory Car List size : " +
> str(len(vw_bra_factory.car_list)))
> print("Actual Car List size         : " +
> str(len(vw.factory_list[0].car_list)))
>
> print("## And another.")
> citi_golf = vw_bra_factory.create_car("Citi golf")
> print("vw_bra_factory Car List size : " +
> str(len(vw_bra_factory.car_list)))
> print("Actual Car List size         : " +
> str(len(vw.factory_list[0].car_list)))
> print("## 'vw_bra_factory' must have lost its C++ reference it had to
> 'vw.factory_list[0]' when I created a new factory. Why?")
>
>
> *Python Output:*
>
> NOT EQUAL
> *## I expected them to be the same reference..?*
> vw_bra_factory Car List size : 1
> Actual Car List size         : 1
> *## This still works. Maybe the python objects differ, but refer to the
> same C++ object. I can live with that.*
> vw_bra_factory Car List size : 0
> Actual Car List size         : 1
> *## .. what? why? brazil py object has no cars now? I don't get it. I
> can't have any of that.*
> *## What will happen if I create another car in the brazil factory?*
> vw_bra_factory Car List size : 1
> Actual Car List size         : 1
> *## And another.*
> vw_bra_factory Car List size : 2
> Actual Car List size         : 1
> *## 'vw_bra_factory' must have lost its C++ reference it had to
> 'vw.factory_list[0]' when I created a new factory. Why?*
>
> This is just an example made to reproduce my real work's problem in a
> presentable way. In my real work, python crashes
> after I create a second "factory" and try to add a "car" to the first
> "factory".
> The crash occurs in C++ "create_car" method whan trying to access the
> "factory"'s "car" list.
>
> Does anyone have insight as to what the problem is? Any useful input will
> be greatly appreciated.
>
> Greetings,
> Christoff
>



-- 
Christoff Kok
Software Engineer
Ex Mente

http://www.ex-mente.co.za
christoff.kok at ex-mente.co.za
PO Box 10214
Centurion
0046
South Africa
tel: +27 12 743 6993
tel: +27 12 654 8198
fax: +27 85 150 1341
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20150602/7397bd3d/attachment-0001.html>


More information about the Cplusplus-sig mailing list