删除由 boost::python 暴露的 std::vector 中的一个指针

Posted

技术标签:

【中文标题】删除由 boost::python 暴露的 std::vector 中的一个指针【英文标题】:delete a pointer in std::vector exposed by boost::python 【发布时间】:2015-02-22 02:38:43 【问题描述】:

我有这两个类:

typedef std::vector<Entity *> EntityPtrVector;

class A

private:
    EntityPtrVector entity_vector;

public:
    void AddEntity(Entity *);
    void RemoveEntity(std::string);
;

class Entity

private:
    std::string name_;

public:
    Entity();
    Entity(std::string);

    std::string GetName(void) const  return name_; 
    void SetName(const std::string& name)  name_ = name; 
;

我像这样通过 boost::python 公开它们:

BOOST_PYTHON_MODULE(my_lib)

    using namespace boost::python;

    class_<EntityPtrVector>("EntityPtrVector")
        .def(vector_indexing_suite<EntityPtrVector>());

    class_<A>("A", init<std::string>())
        .def("AddEntity", &A::AddEntity)
        .def("RemoveEntity", &A::RemoveEntity)
    ;

    class_<Entity>("Entity", init<std::string>())
        .add_property("name", &Entity::GetName, &Entity::SetName)
    ;

AddEntityRemoveEntity的实现是:

void Game::AddEntity(Entity *E)

    entity_vector.push_back(E);


void Game::RemoveEntity(std::string entity_name)

    EntityPtrVector::iterator entity_ptr;

    // Find the entity with the input name
    for(entity_ptr = entity_vector.begin(); entity_ptr != entity_vector.end(); ++entity_ptr)
    
        if((*entity_ptr)->GetName() == entity_name)
        
            break;
        
    
    // Remove the target entity
    if(entity_ptr != entity_vector.end())
    
        delete *entity_ptr;
        entity_vector.erase(entity_ptr);
    

我已经检查过它是否可以在 C++ 下工作而无需暴露于 python。在python中,AddEntity的部分和查找目标实体是成功的,但是它在RemoveEntitydelete *指令处崩溃(我通过在每一行代码后添加日志指令来检查这些)。这是我在 python 中的测试代码:

import my_lib

test_a = my_lib.A("Test A")
test_e = my_lib.Entity("Test Entity")

test_a.AddEntity(test_e)
test_a.RemoveEntity("Test Entity")

我想也许我对std::vector&lt;Entity *&gt; 的曝光不正确,但是我该如何纠正呢?

【问题讨论】:

为什么你在 C++ 和 Python 中使用了 html/javascript 可运行代码 sn-p 块? 你能做一个测试用例吗?也许抽象掉所有的 Python?你的调试器说了什么? 您的代码中没有证据表明您的实体是动态分配的,因此调用delete 会导致非动态分配条目的未定义行为。 哦,谢谢 PaulMcKenzie 和 Yakk,也许我知道它出了什么问题。 【参考方案1】:
test_e = my_lib.Entity("Test Entity")

创建一个拥有 C++ Entity 的 Python 对象。它管理生命周期。

test_a.AddEntity(test_e)

这里我们将test_e包裹的C++对象传递给test_a包裹的C++对象。 C++ 对象存储在A 的向量中。

test_a.RemoveEntity("Test Entity")

这将删除您在上面添加的Entity。但是,test_e 类 * 仍然认为它拥有 Entity,因为它无法被告知您已将所有权转移。但是现在它拥有一个无效的指针。

崩溃发生在删除时,因为 C++ 没有管理该内存——python 是。它不使用 C++ 堆。

您需要对 C++ 代码中的所有权和生命周期管理进行更牢固的设计。永远不要 delete 你没有 new,python 案例中的 C++ 代码永远不会 newed Entity

【讨论】:

也就是说,例如我需要一个成员函数,它可以新建一个Entity并在C++中返回它的点,然后把这个点给AddEntity对吗? @Ddavid 您需要停止通过原始 C++ 指针传递对象的所有权。如果您拥有所有权,请使用类型化的拥有智能指针。然后让接口在 Python 中工作。

以上是关于删除由 boost::python 暴露的 std::vector 中的一个指针的主要内容,如果未能解决你的问题,请参考以下文章

用 boost.python 暴露 std::vector<double>

std::atomic 作为类成员:使用 boost/python.hpp 时使用已删除的函数错误

Boost python,将原始指针与托管指针进行比较?

Boost不将模块暴露给python

Boost.Python - 暴露一个类

Boost.Python 列出所有暴露的类和属性