使用Python / C API在我的C ++代码中减少PyObject*
时出现分段错误,我无法弄清楚原因。我正在使用C ++和Python 2.7。我正在使用新式类来支持Python 3的兼容性。
我的目标是创建一个C ++类MyClass
,作为Python模块中定义的类的包装器。在MyClass
构造函数中,我传入Python模块的名称,导入模块,找到类(始终具有预定义的名称PyClass
),并调用该类来创建实例它的。然后,我将生成的PyObject*
存储在MyClass
中,以备将来使用。在MyClass
析构函数中,我减少了存储PyObject*
以避免内存泄漏。
我已经验证了一切正常,只要找到类并创建它的实例。我甚至已经验证我可以使用其他PyObject*
方法中存储的MyClass
来访问PyClass
中的方法。但是,当析构函数执行递减时,它会导致段错误。
以下是我的代码示例。我也在适当的时候在其他地方拨打Py_Initialize()
和Py_Finalize()
,为简洁起见,我遗漏了一些错误检查代码:
MyPythonModule.py
class PyClass:
pass
MyClass.h
class MyClass {
public:
MyClass(const char* modulename);
~MyClass();
private:
void* _StoredPtr;
};
MyClass.cpp
#include <Python.h>
#include <iostream>
#include "MyClass.h"
MyClass::MyClass(const char* modulename) {
_StoredPtr = NULL;
PyObject *pName = NULL, *pModule = NULL, *pAttr = NULL;
// Import the Python module.
pName = PyString_FromString(modulename);
if (pName == NULL) {goto error;}
pModule = PyImport_Import(pName);
if (pModule == NULL) {goto error;}
// Create a PyClass instance and store a pointer to it.
pAttr = PyObject_GetAttrString(pModule, "PyClass");
if (pAttr == NULL) {goto error;}
_StoredPtr = (void*) PyObject_CallObject(pAttr, NULL);
Py_DECREF(pAttr);
if (_StoredPtr == NULL) {goto error;}
error:
if (PyErr_Occurred()) {PyErr_Print();}
Py_XDECREF(pName);
Py_XDECREF(pModule);
return;
}
MyClass::~MyClass() {
std::cout << "Starting destructor..." << std::endl;
Py_XDECREF((PyObject*)(_StoredPtr));
std::cout << "Destructor complete." << std::endl;
}
我知道我可以通过省略析构函数中的Py_XDECREF()
来避免段错误,但我害怕导致内存泄漏,因为我不明白为什么会发生这种情况。我可以在其他_StoredPtr
方法中成功使用MyClass
似乎特别奇怪,但我无法减少它。
我还尝试将导入模块的PyObject*
存储在MyClass
中并保持不变,直到_StoredPtr
递减为止,但_StoredPtr
递减仍为段错误。我尝试评论Py_DECREF(pAttr);
行,但这没有用。
正如我所提到的,我可以使用PyClass
检索_StoredPtr
中的方法,我也尝试将这些方法存储在MyClass
中并在析构函数中对它们进行递减。当我这样做时,我可以减去_StoredPtr
,但是当我尝试减去方法PyObject*
时,它就会出现段错误。如果我使用多种方法执行此操作,则无论我将它们置于何种顺序,它始终是导致段错误的最后一个递减。
有关此处发生的事情的任何见解?
答案 0 :(得分:0)
小心使用PyErr_Print(),如果有正在播放的PyExc_SystemExit,它可以退出。
答案 1 :(得分:0)
这对我有用
#include <Python.h>
#include <iostream>
#include "MyClass.h"
MyClass::MyClass(const char* modulename) {
_StoredPtr = NULL;
PyObject *pName = NULL, *pModule = NULL, *pAttr = NULL;
// Import the Python module.
pName = PyString_FromString(modulename);
if (pName == NULL) {goto error;}
pModule = PyImport_Import(pName);
if (pModule == NULL) {goto error;}
// Create a PyClass instance and store a pointer to it.
pAttr = PyObject_GetAttrString(pModule, "PyClass");
if (pAttr == NULL) {goto error;}
_StoredPtr = (void*) PyObject_CallObject(pAttr, NULL);
Py_DECREF(pAttr);
if (_StoredPtr == NULL) {goto error;}
else{
// do something with _StoredPtr
Py_XDECREF((*PyObject)_StoredPtr)
}
error:
if (PyErr_Occurred()) {PyErr_Print();}
Py_XDECREF(pName);
Py_XDECREF(pModule);
return;
}
MyClass::~MyClass() {}
我基本上将XDECREF从析构函数之外移到了使用PyObject的函数中。