首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何创建和使用存储为c++对象的python对象?

如何创建和使用存储为c++对象的python对象?
EN

Stack Overflow用户
提问于 2020-05-12 07:59:23
回答 1查看 108关注 0票数 1

因此,正如标题所暗示的,我正在处理一个c++项目,在该项目中,我需要调用一个python模块,将其另存为一个对象,并多次调用它的一个方法。您可以在下面找到该类的代码,其中包含python对象。目前,它是在一个for循环中实现的,该循环多次调用该方法。实例化类以及对类的第一次调用都可以很好地工作。然而,在完成for循环的第一个循环后,程序崩溃,并出现" free ():invalid size“或有时"double free or corruption”的错误。我试着使用valgrind来追踪内存泄漏,但我得到了很多pythonCApi调用的痕迹,我并不是真的理解。

代码语言:javascript
运行
复制
#include <python2.7/Python.h>
#include <iostream>
#include <algorithm>
#include "predictor.hpp"

using namespace std;


predictor::predictor()
{
  Py_Initialize();

  pName = PyString_FromString("predictor");

  pModule = PyImport_Import(pName);

  Py_XDECREF(pName);

  if (pModule == nullptr) {
    PyErr_Print();
    std::cerr << "Fails to import the module predictor, check installation.\n";
  }

  // dict is a borrowed reference.
  dict = PyModule_GetDict(pModule);
  if (dict == nullptr) {
    PyErr_Print();
    std::cerr << "Fails to get the dictionary, check predictor installation.\n";
    Py_XDECREF(pModule);
  }
  Py_XDECREF(pModule);

  // Builds the name of a callable class
  python_class = PyDict_GetItemString(dict, "Predictor");
  if (python_class == nullptr || python_class == NULL) {
    PyErr_Print();
    std::cerr << "Fails to get the Python class, check predictor installation.\n";
    Py_XDECREF(dict);
  }
  Py_XDECREF(dict);

  // Creates an instance of the class
  if (PyCallable_Check(python_class)) {
    object = PyObject_CallObject(python_class, nullptr);
    if (object == NULL)
    {
        cerr << "Fails to create object.";
        Py_XDECREF(python_class);
    }
    Py_XDECREF(python_class);
} else {
    PyErr_Print();
    std::cout << "Cannot instantiate the Python class" << std::endl;
    Py_XDECREF(python_class);
}

pMethod = PyString_FromString("predict_all");

}


predictor::~predictor()
{

  Py_XDECREF(pMethod);

  Py_XDECREF(object);
  Py_Finalize();

}


long predictor::predict(string rule)
{

  PyObject *pRule = PyString_FromString(rule.c_str());
  PyObject *value = PyObject_CallMethodObjArgs(object, pMethod, pRule, NULL);

  long endValue = PyInt_AsLong(value);

  if (endValue == -1)
  {
    if(!PyErr_Occurred())
    {

        PyErr_Print();
        cerr << "";

        Py_XDECREF(value);
        Py_XDECREF(pRule); 

        return NULL;
    }

    //PyErr_Print();

  }

  Py_XDECREF(value);
  Py_XDECREF(pRule); 

  return endValue;}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-12 15:42:16

编写Python C/C++代码的最关键部分是正确的引用计数。Python区分不同类型的引用,即newstolenborrowed引用。

对于您调用的每个API函数,您必须检查文档以查看它返回的引用类型(如果有)。

新的引用属于调用者,所以使用Py_XDECREF通过减少引用计数来释放对象是正确的。请确保不要多次调用Py_XDECREF,除非您在两次调用之间增加了引用计数。在错误处理中,Py_XDECREF(pModule)会发生两次,例如,因为在错误情况下没有返回,所以只需继续。

借用的引用归其他人所有,引用计数不会为您递增。因此,只有在执行此操作之前您自己增加了引用计数,调用Py_XDECREF才有效。

PyModule_GetDict(pModule)返回一个借用的引用。您不会递增引用计数,但稍后会使用Py_XDECREF(dict)递减它。对于PyDict_GetItemString(dict, "predictor")也是如此,它返回一个借用的引用,但您使用Py_XDECREF(python_class)递减它。

我的假设是,在这两种情况下(dictpython_class),借用的引用都属于您使用PyImport_Import(pName)导入的模块pModule。因此,只要您使用的是pModule拥有的借用引用,就很可能不能减少pModule引用计数。一旦你不再使用这些借用的引用,就使用Py_XDECREF发布pModule。或者,您可以递增借用的引用的引用计数,但只要您保持pModule不变,就不需要这样做。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61741451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档