简体   繁体   中英

Calling Python code from C++ gives unexpected number of references

I am running the C++ code below and it works fine if I comment out the Py_XDECREF lines. I suppose, however, that it causes memory leaks in such a case. When the Py_XDECREF lines are commented in, the code execution behaves unexpected. First of all, I don't understand the number of references. Why is there for example seven references to pName? Second, why do I get a negative refcount-error when using Py_XDECREF ? As I understood Py_XDECREF should be safe in this respect, and the current error should only be possible if I use Py_DECREF ? Third and most importantly: How to I change the code so that it works?

When executing the line Py_XDECREF(pDict); I get the following error:

D:\a\1\s\Include\object.h:497: _Py_NegativeRefcount: Assertion failed: object has negative ref count
<object at 0000018CA6726410 is freed>
Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized
Current thread 0x000086b0 (most recent call first):
<no Python frame>

Here is the code:

#include <Python.h> 
#include <stdio.h>
#include <iostream>
#include <sstream>

int main(int argc, char** argv) {

    // 1) initialize Python
    Py_Initialize();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\".\")");
    PyRun_SimpleString("print(sys.path)");

    // 2) Import the python module
    PyObject* pName = PyUnicode_FromString("module1");
    assert(pName != NULL);
    PyObject* pModule = PyImport_Import(pName);
    assert(pModule != NULL);

    // 3) Get a reference to the python function to call
    PyObject* pDict = PyModule_GetDict(pModule);
    assert(pDict != NULL);
    PyObject* pFunc = PyDict_GetItemString(pDict, (char*)"getInteger");
    assert(pFunc != NULL);

    // 4) Call function
    PyObject* pValue = PyObject_CallObject(pFunc, NULL);

    Py_XDECREF(pValue);
    Py_XDECREF(pFunc);
    Py_XDECREF(pDict);
    Py_XDECREF(pModule);
    Py_XDECREF(pName);

    Py_Finalize();

The imported module is called module1.py and has this content:

def getInteger():
    print('Python function getInteger() called')
    c = 100*50/30
    return c

PyModule_GetDict returns a borrowed reference . You should not decrement the reference count of a borrowed reference, so the error is entirely expected: the ref count can't be decremented because it was already zero.

However, you can simplify it by using PyObject_GetAttrString(pModule, "getInteger") directly instead of going through pDict .

You should also write proper error handing, since assert only works in Debug builds and becomes no-op in Release mode.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM