尝试读取在 Python 中创建的对象并传递到 C++ 端的 std::vector 然后返回到 Python 时出现访问冲突

2024-02-03

在 Windows 10 上使用 VS 2019、Python 3.7 64 位和 pybind11 2.4.3 时,我遇到了以下问题:

当我使用 pybind11 创建对象时py::class_在 Python 端并将其直接传递给 C++ 端的方法并将其存储在 std::vector 中,稍后尝试从 Python 读出该对象会导致Access violation - no RTTI data。如果 Python 代码首先将创建的对象存储在 Python 变量中,然后将其传递给 C++,则随后从 Python 进行的访问将按预期进行。

我在使用 pybind11 和 C++ 方面没有太多经验,所以我可能犯了一个简单的错误,希望获得有关如何设置 C++ 和 pybind11 用法的任何帮助,以便不需要使用变量的 Python 解决方法,而且我不需要没有发生任何访问冲突。

下面是一些代码细节,C++代码是

#include <iostream>

#include <vector>

#include <pybind11/pybind11.h>

using namespace std;


class XdmItem;

class XdmValue {

public:

    virtual XdmItem* itemAt(int n);

    virtual int size();

    void addXdmItem(XdmItem* val);


protected:
    std::vector<XdmItem*> values;
};

void XdmValue::addXdmItem(XdmItem* val) {
    values.push_back(val);
}

XdmItem* XdmValue::itemAt(int n) {
    if (n >= 0 && (unsigned int)n < values.size()) {
        return values[n];
    }
    return NULL;
}

int XdmValue::size() {
    return values.size();
}

class XdmItem : public XdmValue {

public:

    int size();

};

int XdmItem::size() {
    return 1;
}


namespace py = pybind11;

PYBIND11_MODULE(UseClassHierarchyAsPythonModule, m) {


    py::class_<XdmValue>(m, "PyXdmValue")
        .def(py::init<>())
        .def("size", &XdmValue::size)
        .def("item_at", &XdmValue::itemAt)
        .def("add_item", &XdmValue::addXdmItem);

    py::class_<XdmItem, XdmValue>(m, "PyXdmItem")
        .def(py::init<>())
        .def("size", &XdmItem::size);



#ifdef VERSION_INFO
    m.attr("__version__") = VERSION_INFO;
#else
    m.attr("__version__") = "dev";
#endif
}

完美运行的Python代码是

import UseClassHierarchyAsPythonModule

value = UseClassHierarchyAsPythonModule.PyXdmValue()

print(value, type(value))

print(value.size())

item = UseClassHierarchyAsPythonModule.PyXdmItem()

value.add_item(item)

print(value.size())

item0 = value.item_at(0)

print(item, type(item))

而下面的代码会导致Access violation - no RTTI data!:

import UseClassHierarchyAsPythonModule

value = UseClassHierarchyAsPythonModule.PyXdmValue()

print(value, type(value))

print(value.size())

value.add_item(UseClassHierarchyAsPythonModule.PyXdmItem())

print(value.size())

item0 = value.item_at(0)

print(item, type(item))

It gives

  Message=Access violation - no RTTI data!
  Source=C:\SomePath\AccessViolation.py
  StackTrace:
  File "C:\SomePath\AccessViolation.py", line 13, in <module>
    item0 = value.item_at(0)

如果我启用本机代码调试,堆栈跟踪将包含 pybind C++ 代码,并且是

>   UseClassHierarchyAsPythonModule.pyd!pybind11::polymorphic_type_hook<XdmItem,void>::get(const XdmItem * src, const type_info * & type) Line 818  C++
    UseClassHierarchyAsPythonModule.pyd!pybind11::detail::type_caster_base<XdmItem>::src_and_type(const XdmItem * src) Line 851 C++
    UseClassHierarchyAsPythonModule.pyd!pybind11::detail::type_caster_base<XdmItem>::cast(const XdmItem * src, pybind11::return_value_policy policy, pybind11::handle parent) Line 871  C++
    UseClassHierarchyAsPythonModule.pyd!pybind11::cpp_function::initialize::__l2::<lambda>(pybind11::detail::function_call & call) Line 163 C++
    UseClassHierarchyAsPythonModule.pyd!pybind11::handle <lambda>(pybind11::detail::function_call &)::<lambda_invoker_cdecl>(pybind11::detail::function_call & call) Line 100   C++
    UseClassHierarchyAsPythonModule.pyd!pybind11::cpp_function::dispatcher(_object * self, _object * args_in, _object * kwargs_in) Line 624 C++
    [External Code] 
    AccessViolation.py!<module> Line 13 Python

知道我的 C++/pybind11 使用有什么问题吗?


注意:我目前还不是PyBind11专家,我刚刚读了这个问题并试图找出原因可能是什么。
我的猜测是,区别在于,在它不起作用的情况下,Python对象是在之前创建的add_item调用(也是如此C++包装了一个)然后就在调用之后它被垃圾收集(并且与它一起C++包裹一个),产生未定义的行为(无效的指针)。
相反,在它起作用的情况下,对象不会被垃圾收集,因为它被“保存”在item (its refcount大于 0),因此C++还存在被包裹的对象。 Adelete item刚过value.add_item(item)应该重现错误行为。

根据[ReadTheDocs.PyBind11]:函数 - 保持活动状态 https://pybind11.readthedocs.io/en/stable/advanced/functions.html#keep-alive:

一般来说,当 C++ 对象是任何类型的容器并且另一个对象被添加到容器中时,需要此策略。keep_alive<Nurse, Patient>表示带索引的参数Patient应该至少在带有索引的参数之前保持活动状态Nurse被垃圾收集器释放。

所以,解决方案是使UseClassHierarchyAsPythonModule.PyXdmItem对象持久存在,直到容器被销毁(请注意,这可能会使对象在内存中保留的时间比预期长,可能有更干净的方法来实现此目的),那就是通过在add_item:

...

.def("add_item", &XdmValue::addXdmItem, py::keep_alive<1, 2>());
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试读取在 Python 中创建的对象并传递到 C++ 端的 std::vector 然后返回到 Python 时出现访问冲突 的相关文章

随机推荐

  • postgreSQL中的@@Fetch_status

    我正在将数据库从 MS SQL Server 传输到 PostgreSQL 但此触发器有问题 CREATE TRIGGER added clients ON client FOR INSERT AS BEGIN DECLARE cursor
  • 如何强类型组合 mixin?

    我正在尝试使用函数组合通过 mixin 向对象添加行为 const pipe funcs args any gt any gt initial any gt funcs reduce object fn gt fn object initi
  • 快速,将文件发送到服务器

    我正在学习 swift 我使用下面的代码向服务器发送请求 它适用于简单的请求 我从服务器得到响应 我的问题是我无法将文件发送到服务器 code let parameters parameter let request NSMutableUR
  • 播放后重定向 html5 视频

    我有一个 html 5 视频 我删除了控制按钮并添加了 js 代码 以便用户在单击视频时播放视频 我需要做的是绑定一个额外的脚本 该脚本将在视频播放后重定向页面 而无需重新加载页面 下面是我的js代码 function play var v
  • 如何获取colspan的值

    我尝试过不同的 jQuery 方法 var num this attr colspan text var num this attr colspan val var num this td colspan val var num this
  • 在c#中将字符串转换为十进制

    我在使用decimal parse 将字符串转换为十进制值时遇到一些问题 这是我的代码行 fixPrice decimal Parse mItemParts Groups price Value Replace Replace Replac
  • 开发人员是否需要为在 Windows Azure Marketplace 上发布 SaaS 应用程序付费?

    目前我正在构建一个简单的 SaaS 驱动的 TMS 目的是在 Windows Azure Marketplace 中发布它 我无法找到任何定价 微软是否向开发者收取发布费用 是按月计算的吗 或者 Windows Azure 上托管的所有应用
  • OpenGL-OpenCL 互操作传输时间 + 位图纹理

    两部分问题 我正在开展一个学校项目 使用生命游戏作为实验 gpgpu 的工具 我使用 OpenCL 和 OpenGL 进行实时可视化 目标是让这个东西尽可能大 更快 经过分析 我发现帧时间主要由 CL 获取和释放 GL 缓冲区决定 并且时间
  • JavaScript 初学者遇到的引号问题

    我正在尝试从一本书 Jeremy McPeak 的 Beginner JavaScript 中学习 JS 但我坚持使用以下代码 html 中的结果是这样的 56 02 degrees centigrade is 56 as an integ
  • 如何分发带有依赖库的 Mac OS X?

    我有一个程序 特别是我的条目SO DevDays 倒计时应用挑战 https meta stackexchange com questions 20420 countdown app for devdays 21659 21659 它依赖于
  • 基于多个文件的存在激活 Maven 配置文件

    我想根据多个文件的存在来激活配置文件 在下面的示例中 如果两个文件都被激活 我希望配置文件被激活my marker and another marker exists
  • 包恢复失败。回滚包更改

    当我尝试在 VS2017 中为 asp net core 安装任何 nuget 包时 它不断显示每个 包的 包恢复失败 回滚包更改 您可以执行以下步骤 VS Tools Options Nuget 包管理器 General 清除所有 Nug
  • Gradle编译:如何从依赖关系中识别组和模块?

    有时 我不想添加所有依赖项 因此我需要从依赖项中排除一些依赖项 例如 compile com google http client google http client 1 20 0 exclude group org apache htt
  • ODBC Teradata 驱动程序 HY001 内存分配错误。什么意思?

    我正在使用 python 脚本 该脚本使用 teradata python 模块和类似于下面的脚本将一批数据插入 Teradata 它使用 ODBC 连接 偶尔会出现以下错误 HY001 Teradata ODBC Teradata Dri
  • 将 MutationGroup 流式传输到 Spanner 中

    我正在尝试使用 SpannerIO 将 MutationGroups 流式传输到扳手中 目标是每 10 秒写入新的 MuationGroup 因为我们将使用 Spanner 来查询近期 KPI 当我不使用任何 Windows 时 出现以下错
  • 我怎样才能记住所有CSS简写?

    我从未忘记并且总是使用速记margin and padding因为它是顺时针运行的 但是你怎么记得其他的呢 你是否尽可能使用 CSS 简写 记住不同简写的最佳方法是什么 Update 我还发现了 2 个很好的速记备忘单 Png http w
  • IntelliJ IDEA 在调试时停留在“收集数据”

    我正在使用 IntelliJ IDEA 来调试远程 tomcat 应用程序 之前效果很完美 然而 最近一段时间 它总是卡在 收集数据 上 尽管数据很小 我在这个网站上搜索过 并尝试过 Intellij IDEA在调试模式下非常慢 在正常模式
  • Autofac SingleInstance 不工作

    我正在尝试获得一个与 Autofac 一起使用的 Singleton 实例 我正在用 Winforms 做一个准 mvvm 类型的事情 只是一个实验 所以不要挂断它 但我正在尝试让我的模型成为单个实例 并在命令中引用 此处的 IComman
  • 如何使用Python套接字发送SIP消息

    我需要使用 Python 套接字发送 SIP 消息 我已经让客户端向服务器发送一些内容 但我无法让客户端向服务器发送 SIP 消息 INVITE usr bin python import socket R IP 192 168 2 1 R
  • 尝试读取在 Python 中创建的对象并传递到 C++ 端的 std::vector 然后返回到 Python 时出现访问冲突

    在 Windows 10 上使用 VS 2019 Python 3 7 64 位和 pybind11 2 4 3 时 我遇到了以下问题 当我使用 pybind11 创建对象时py class 在 Python 端并将其直接传递给 C 端的方