简体   繁体   English

Python中的Boost.Python C ++对象参考:意外行为

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

I am having an issue with Boost.Python with a very simple use case. 我在一个非常简单的用例中遇到了Boost.Python的问题。

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. 我正在返回对对象的引用,并且由于某种原因,看来我的python对象在某个阶段失去了其C ++对象的引用。

Please see my example below reproducing this issue. 请在下面的示例中重现此问题。

C++ Code: 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 Code: 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 Output: 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?

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". 在我的实际工作中,在创建第二个“ factory”并尝试将“ car”添加到第一个“ factory”之后,python崩溃了。 The crash occurs in C++ "create_car" method whan trying to access the "factory"'s "car" list. 崩溃发生在试图访问“工厂”的“汽车”列表的C ++“ create_car”方法中。

Does anyone have insight as to what the problem is? 有谁对问题出在什么方面有见识? Any useful input will be greatly appreciated. 任何有用的输入将不胜感激。

Thanks to someone on the mailing list for figure the problem out: 感谢邮件列表中的某人找出了问题所在:

It works when I reserve the vectors sizes to eg 32. 当我将向量大小保留为例如32时,它将起作用。

It also works if I allocate the objects stored in the vectors on the heap. 如果我将存储在向量中的对象分配给堆,它也可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM