pybind11STL自动转换器中断std::list指针



我有一个C++库,它处理(除其他外(一系列包装器,我一直在使用pybind11将这些包装器转换为Python。库的其余部分操作指向指针列表的指针:std::list<Symbol*>*。问题是,当试图将Python列表自动转换为此C++列表,然后初始化ParamMap(一个在C++侧保存列表的对象(时,列表的指针会完全混乱。GDB中的检查显示;下一个对象指针";的对象无效,这会导致遍历列表时出现segfault。

在C++端没有对象被释放的迹象,因为列表容器ParamMap和列表对象Symbol的析构函数都没有被调用。我推断问题可能是Python过度主动地删除C++仍在使用的对象,但我尝试过py::return_value_policy::referencepy::keep_alive等对象术语,但它们并没有解决这个问题。这里出了什么问题?不幸的是,在C++端更改列表类型不是一个选项,但我非常感谢在Python端提供一些帮助。非常感谢。

这里有一些最小的复制代码:

符号.hpp

#include <string>
class Symbol {
private:
std::string val1;
int val2;
public:
Symbol(std::string con1, int con2) : val1(con1), val2(con2) {}
};

ParamMap.hpp

#include <list>
#include "Symbol.hpp"
class ParamMap {
private:
std::list<Symbol*>* lst;
int otherData;
public:
ParamMap(std::list<Symbol*>* symbolList, int dat) : lst(symbolList), otherData(dat)  {}
std::list<Symbol*>* getSymbols() { return lst; }
int getOtherData() { return otherData; }
};

Query.cpp

#include <iostream>
#include "ParamMap.hpp"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
void getSymbolListSize(ParamMap* map) {
std::cout << "Entering query method" << std::endl;
auto sz = map->getSymbols()->size(); // SEGFAULT OCCURS WHEN GETTING SIZE
std::cout << "Got size successfully. Size = " << sz << std::endl;
}
PYBIND11_MODULE(list_test, handle) {
handle.def("getSymbolListSize", &getSymbolListSize);
py::class_<ParamMap>(handle, "ParamMap")
.def(py::init<std::list<Symbol*>*, int>(), py::keep_alive<1, 2>())
.def("getOtherData", &ParamMap::getOtherData)
.def("getSymbols", &ParamMap::getSymbols);
py::class_<Symbol>(handle, "Symbol")
.def(py::init<std::string, int>());
}

测试.py

import list_test as p
# Creating a list of some random symbols
symbol_list = []
symbol1 = p.Symbol("Hello", 1)
symbol_list.append(symbol1)
symbol2 = p.Symbol("World", 2)
symbol_list.append(symbol2)
# Creating a parammap and passing it the symbol list
pm = p.ParamMap(symbol_list, 71)
print("Symbol list and ParamMap init'd successfully")
# Here, calling Query.cpp's only method
sz = p.getSymbolListSize(pm)
print(sz)

我不太了解pybind11是如何发挥其魔力的,因此我无法帮助您了解发生了什么。然而,我有一种感觉,即使您的代码只使用指向列表的指针,pybind也会尝试构建列表。如果我是你,我会认为这是一个pybind错误,并将其作为一个问题发布在他们的github页面上。

根据您的代码,这样做似乎有效(尽管不是很干净(:

#include <list>
#include "Symbol.hpp"
class ParamMap {
private:
std::list<Symbol*>* lst;
int otherData;
public:
ParamMap(std::list<Symbol*> *symbolList, int dat) : lst(symbolList), otherData(dat)  {
lst = new std::list<Symbol *>;
for(auto s : *symbolList) {
lst->push_back(s);
}
}
~ParamMap() {
delete lst;
}
std::list<Symbol*>* getSymbols() { return lst; }
int getOtherData() { return otherData; }
};

我不知道谁应该管理指向列表的生存期,所以你可能想删除析构函数,以防其他人应该取消分配该列表。

最新更新