[英]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.