Python 在返回 C++ 映射值时崩溃

Posted

技术标签:

【中文标题】Python 在返回 C++ 映射值时崩溃【英文标题】:Python crashes on returning an C++ map value 【发布时间】:2018-06-26 11:37:00 【问题描述】:

我正在编写一个测试以将数据保存在 C++ 映射中。我正在使用 Python C-Api。 添加 int 值并获取地图的长度是没有问题的。 但是,当我从地图中获取一个值并想要将其返回给 Python 时,解释器就会崩溃。 这是我的代码:

    //some includes 
    int VerboseLog = 99;
    typedef map<const char*, int> SessionKeeper;
    static SessionKeeper openSessions;

    static PyObject* getSession(PyObject* self, PyObject* args) 
        cout << "get" << endl;
        const char *key;

        if (!PyArg_ParseTuple(args, "z*", &key)) 
            PyErr_SetString(PyExc_Exception, "UUID konnte nicht ausgelesen werden");
            PyErr_PrintEx(1);
            return NULL;
        

        int r = openSessions.at(key);
        return Py_BuildValue("i", r);
    

    static PyObject *addSession(PyObject* self, PyObject* args) 
        cout << "Hello" << endl;
        const char  *key;
        int toAppend;

        if (!PyArg_ParseTuple(args, "si", &key, &toAppend)) 
            PyErr_SetString(PyExc_Exception, "Ein Parameter konnte nicht ausgelesen werden");
            PyErr_PrintEx(1);
            return NULL;
        

        openSessions[key] = toAppend;
        cout << openSessions.size() << endl;
        cout << openSessions[key] << endl;
        Py_RETURN_NONE;
    

    static PyObject* length(PyObject *self)
        cout << "length: ";
        int i = openSessions.size();
        return Py_BuildValue("i",i);
    

    static PyMethodDef SessionKeeper_methods[] = 
        /*Note the third entry (METH_VARARGS). This is a flag telling the interpreter the calling convention
        to be used for the C function. It should normally always be METH_VARARGS or METH_VARARGS | METH_KEYWORDS;
        a value of 0 means that an obsolete variant of PyArg_ParseTuple() is used.*/
         "length", (PyCFunction)length, METH_VARARGS, "return length of a Session" ,
         "addSession", (PyCFunction)addSession, METH_VARARGS, "add a Session." ,
         "getSession", (PyCFunction)getSession, METH_VARARGS, "get a Session" ,
         NULL 
    ;

    static PyModuleDef sessionKeeperMod = 
        PyModuleDef_HEAD_INIT,
        u8"SessionKeeper",
        NULL,
        -1,
        SessionKeeper_methods
    ;

    static PyModuleDef CpluplusModules_ModDef = 
        PyModuleDef_HEAD_INIT,
        u8"CPlusPlusMouldes",
        u8"Enthält alle Erweietrungen",
        -1,
        NULL, NULL, NULL, NULL, NULL
    ;

    PyMODINIT_FUNC PyInit_CPlusPlusModules(void) 
            PyObject* m, *sessionMod;

            if (PyType_Ready(&TAModulType) < 0)
                return NULL;

            if (PyType_Ready(&DatabaseReader_Type) < 0)
                return NULL;

            if (!(sessionMod = PyModule_Create(&sessionKeeperMod))) 
                cout << "fail" << endl;
                return NULL;
            

            m = PyModule_Create(&CpluplusModules_ModDef);
            if (m == NULL)
                return NULL;

            Py_INCREF(&TAModulType);
            Py_INCREF(&DatabaseReader_Type);

            PyModule_AddObject(m, "TAModul", (PyObject *)&TAModulType);
            PyModule_AddObject(m, "DBReader", (PyObject *)&DatabaseReader_Type);
            PyModule_AddObject(m, "SessionKeeper", sessionMod);

            return m;
    

其他模块(DBReader 和 TAModule)工作正常。目标是保护地图中的 PythonObjects(包含 DbReader 对象和 TAModul 对象)。

但是回到我的问题,为什么 getSession 在返回时会使解释器崩溃?以及为什么长度函数可以正常工作。

【问题讨论】:

【参考方案1】:

map&lt;const char*,...&gt; 将 match based on the address of the string rather than the contents。因此,at 很可能会失败并抛出 C++ out_of_range 异常。

你应该从换行开始

int r = openSessions.at(key);

使用 try catch 块,阻止 out_of_range 异常通过 Python 解释器(不是 C++,因此无法处理)传播。

然后您应该更改映射以匹配字符串内容上的键。最简单的方法是使用map&lt;std::string,int&gt;

【讨论】:

谢谢这是问题的一部分,我还不得不在解析函数中使用“z*”的“s”状态

以上是关于Python 在返回 C++ 映射值时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Swift:在展开可选值时发现映射函数为零

Obj-C 框架返回 nil,并让我的 Swift 代码崩溃,说“致命错误:在展开可选值时意外发现 nil”

Obj-C 框架返回 nil,并让我的 Swift 代码崩溃,说“致命错误:在展开可选值时意外发现 nil”

映射列值时忽略缺失值

如何使用 swig 将 c++ int** 返回值类型映射到 python

有没有办法通过 C++ 中的 OUT 参数接收 Python 中的返回值?