Python中的Boost.Python C ++对象引用:意外行为

时间:2015-05-28 08:21:42

标签: python c++ boost-python

我遇到了Boost.Python的一个问题,只是一个非常简单的用例。

我正在返回一个对象的引用,似乎我的python对象由于某种原因在某个阶段丢失了它的C ++对象的引用。

请参阅下面的示例,重现此问题。

C ++代码:

#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代码:

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输出:

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?

这只是一个以一种可行的方式重现我的实际工作问题的例子。在我的实际工作中,python崩溃了 在我创建第二个&#34;工厂&#34;并尝试添加&#34;汽车&#34;到第一个&#34;工厂&#34;。 崩溃发生在C ++&#34; create_car&#34;试图进入&#34;&#34;&#34;&#34;&#34;汽车&#34;列表。

有没有人能够了解问题所在?任何有用的输入将不胜感激。

1 个答案:

答案 0 :(得分:0)

感谢邮件列表中的某人想出问题:

当我将矢量大小保留为例如32。

如果我在堆上分配存储在向量中的对象,它也可以工作。