如何创建和使用存储为 c++ 对象的 python 对象?
How to create and use a python object stored as a c++ object?
所以正如标题所暗示的那样,我正在处理一个 c++ 项目,我需要调用一个 python 模块,将其保存为对象,并多次调用它的方法之一。您可以在下面找到包含 python 对象的类的代码。目前,它是在多次调用该方法的 for 循环中实现的。实例化类以及第一次调用类都可以正常工作。但是,在完成 for 循环的第一个循环后,程序崩溃并显示类似"free((:无效大小"或有时"双释放或损坏"的错误。我尝试使用 valgrind 来尝试跟踪内存泄漏,但我得到了很多我不太了解的 pythonCApi 调用的痕迹。
#include <python2.7/Python.h>
#include <iostream>
#include <algorithm>
#include "predictor.hpp"
using namespace std;
predictor::predictor()
{
Py_Initialize();
pName = PyString_FromString("predictor");
pModule = PyImport_Import(pName);
Py_XDECREF(pName);
if (pModule == nullptr) {
PyErr_Print();
std::cerr << "Fails to import the module predictor, check installation.n";
}
// dict is a borrowed reference.
dict = PyModule_GetDict(pModule);
if (dict == nullptr) {
PyErr_Print();
std::cerr << "Fails to get the dictionary, check predictor installation.n";
Py_XDECREF(pModule);
}
Py_XDECREF(pModule);
// Builds the name of a callable class
python_class = PyDict_GetItemString(dict, "Predictor");
if (python_class == nullptr || python_class == NULL) {
PyErr_Print();
std::cerr << "Fails to get the Python class, check predictor installation.n";
Py_XDECREF(dict);
}
Py_XDECREF(dict);
// Creates an instance of the class
if (PyCallable_Check(python_class)) {
object = PyObject_CallObject(python_class, nullptr);
if (object == NULL)
{
cerr << "Fails to create object.";
Py_XDECREF(python_class);
}
Py_XDECREF(python_class);
} else {
PyErr_Print();
std::cout << "Cannot instantiate the Python class" << std::endl;
Py_XDECREF(python_class);
}
pMethod = PyString_FromString("predict_all");
}
predictor::~predictor()
{
Py_XDECREF(pMethod);
Py_XDECREF(object);
Py_Finalize();
}
long predictor::predict(string rule)
{
PyObject *pRule = PyString_FromString(rule.c_str());
PyObject *value = PyObject_CallMethodObjArgs(object, pMethod, pRule, NULL);
long endValue = PyInt_AsLong(value);
if (endValue == -1)
{
if(!PyErr_Occurred())
{
PyErr_Print();
cerr << "";
Py_XDECREF(value);
Py_XDECREF(pRule);
return NULL;
}
//PyErr_Print();
}
Py_XDECREF(value);
Py_XDECREF(pRule);
return endValue;}
编写 Python C/C++ 代码最关键的部分是正确进行引用计数。Python区分不同类型的引用,即new
,stolen
和borrowed
引用。
对于您调用的每个 API 函数,您必须检查文档以查看它返回的引用类型(如果有(。
新引用属于调用方,因此使用Py_XDECREF
通过减少引用计数来释放对象是正确的。请确保不要多次调用Py_XDECREF
,除非您在两者之间增加了引用计数。在错误处理中,Py_XDECREF(pModule)
发生两次,例如,因为您没有在错误情况下返回,您只需继续。
借用的引用归其他人所有,并且引用计数不会为您增加。因此,调用Py_XDECREF
仅在执行此操作之前自己增加了引用计数时才有效。
PyModule_GetDict(pModule)
返回借用的引用。您不会递增引用计数,但稍后会递减它,Py_XDECREF(dict)
。PyDict_GetItemString(dict, "predictor")
也是如此,它返回一个借用的引用,但你用Py_XDECREF(python_class)
递减它。
我的假设是,在这两种情况下(dict
,python_class
(,借用的引用都归您使用PyImport_Import(pName)
导入的模块pModule
所有。因此,只要您使用pModule
拥有的借用引用,您就很可能不能减少pModule
引用计数。一旦您不再使用这些借用的引用,就使用Py_XDECREF
释放pModule
。或者,您可以增加借用引用的引用计数,但只要您保持pModule
,就没有必要这样做。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 将对象移动到std::shared_ptr
- 代理对象的常量正确性
- 提升 ASIO 无法识别计时器对象
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 如何返回一个类的两个对象相加的结果
- 使用std::函数映射对象方法
- 是否需要删除包含对象的"pair"?
- 如何在自删除后将对象设置为nullptr
- 迭代时从向量和内存中删除对象
- 构造对象的歧义
- 使用"std::unordereded_map"映射到"std::list"对象