我有一个C++库,它处理(除其他外(一系列包装器,我一直在使用pybind11将这些包装器转换为Python。库的其余部分操作指向指针列表的指针:std::list<Symbol*>*
。问题是,当试图将Python列表自动转换为此C++列表,然后初始化ParamMap
(一个在C++侧保存列表的对象(时,列表的指针会完全混乱。GDB中的检查显示;下一个对象指针";的对象无效,这会导致遍历列表时出现segfault。
在C++端没有对象被释放的迹象,因为列表容器ParamMap
和列表对象Symbol
的析构函数都没有被调用。我推断问题可能是Python过度主动地删除C++仍在使用的对象,但我尝试过py::return_value_policy::reference
和py::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; }
};
我不知道谁应该管理指向列表的生存期,所以你可能想删除析构函数,以防其他人应该取消分配该列表。