簡體   English   中英

為什么在使用 Python/C API 時會出現此段錯誤?

[英]Why am I getting this segfault when using the Python/C API?

使用 Python/C API 在我的 C++ 代碼中定義PyObject*時出現分段錯誤,我不知道為什么。 我正在使用 C++ 和 Python 2.7。 我正在使用新式類來實現未來的 Python 3 兼容性。

我的目標是創建一個 C++ 類MyClass作為 Python 模塊中定義的類的包裝器。 MyClass構造函數中,我傳入 Python 模塊的名稱,導入模塊,定位類(它總是有一個預定義的名稱PyClass ),然后調用該類來創建它的實例。 然后我將生成的PyObject*存儲在MyClass以備將來使用。 MyClass析構函數中,我對存儲的PyObject*進行 deref 以避免內存泄漏。

我已經驗證,就定位類並創建它的實例而言,一切都正常工作。 我什至驗證了我可以在其他MyClass方法中使用存儲的PyObject* ,例如,訪問PyClass方法。 但是,當析構函數執行 deref 時,會導致段錯誤。

這是我的代碼示例。 我還在適當的時候在其他地方調用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()來避免段Py_XDECREF() ,但我害怕導致內存泄漏,因為我不明白為什么會發生這種情況。 我可以在其他MyClass方法中成功使用_StoredPtr似乎特別奇怪,但我無法對其進行 deref。

我還嘗試將導入模塊的PyObject*存儲在MyClass並保留它直到_StoredPtr被取消引用,但_StoredPtr取消引用仍然存在_StoredPtr錯誤。 我嘗試注釋掉Py_DECREF(pAttr); 行,但這無濟於事。

正如我提到的,我可以使用_StoredPtr檢索PyClass方法,並且我還嘗試將這些方法存儲在MyClass並在析構函數中取消它們。 當我這樣做時,我可以取消引用_StoredPtr ,但是當我嘗試取消引用該方法的PyObject* 如果我用幾種方法來做到這一點,無論我把它們放在什么順序,總是最后一個 decref 導致段錯誤。

關於這里發生了什么的任何見解?

這對我有用

#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 的函數中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM