为什么我在使用Python / C API时遇到此段错误?

时间:2016-01-25 16:57:06

标签: python c++ python-2.7 python-c-api

使用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*时,它就会出现段错误。如果我使用多种方法执行此操作,则无论我将它们置于何种顺序,它始终是导致段错误的最后一个递减。

有关此处发生的事情的任何见解?

2 个答案:

答案 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的函数中。