尝试读取在 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 时出现访问冲突 的相关文章

  • 大量互斥体对性能的影响

    假设我有一个包含 1 000 000 个元素的数组 以及多个工作线程 每个线程都操作该数组中的数据 工作线程可能会使用新数据更新已填充的元素 但每个操作仅限于单个数组元素 并且独立于任何其他元素的值 使用单个互斥锁来保护整个数组显然会导致高
  • 安塞布尔 + 10.11.6

    我在 非常 干净地安装 10 11 6 时遇到了 Ansible 的奇怪问题 我已经安装了brew zsh oh my zsh Lil snitch 和1password 实际上没有安装其他任何东西 我安装了ansible brew ins
  • 在 Python 中将嵌套字典位置作为参数传递

    如果我有一个嵌套字典 我可以通过索引来获取键 如下所示 gt gt gt d a b c gt gt gt d a b c 我可以将该索引作为函数参数传递吗 def get nested value d path a b return d
  • ASP.NET - Crystal Report Viewer 打印按钮在 ASP.NET 中不起作用

    我正在使用 Visual Studio 2008 但我遇到了水晶报告问题 当我单击打印按钮时 它会将我带到弹出窗口 但未找到页面 弹出的网址是 http localhost aspnet client System Web 2 0 5072
  • 如何删除 pip 安装的所有软件包?

    如何从当前激活的虚拟环境中卸载 pip 安装的所有软件包 我发现这个片段作为替代解决方案 与重新创建 virtualenv 相比 删除库更加优雅 pip freeze xargs pip uninstall y 如果您通过 VCS 安装了软
  • Pandas 中的数据透视表小计

    我有以下数据 Employee Account Currency Amount Location Test 2 Basic USD 3000 Airport Test 2 Net USD 2000 Airport Test 1 Basic
  • 为什么连续抛出 2 个异常不会生成无法访问的代码警告?

    为什么以下代码行不会创建编译器警告 void Main throw new Exception throw new Exception 据我所知 编译器应该通知您无法到达第二个抛出异常 这显然是一个编译器错误 它是在 C 3 0 中引入的
  • MINIX内部碎片2

    我正在用 C 语言编写一些软件 它递归地列出给定目录中的所有文件 现在我需要计算出内部碎片 我花了很长时间研究这个问题 发现 ext2 上的内部碎片只发生在最后一个块中 我知道理论上你应该能够从索引节点号获得第一个和最后一个块地址 但我不知
  • 如何在Windows窗体中打开进程

    我想在我的 Windows 窗体应用程序中打开进程 例如 我希望当用户按下 Windows 窗体容器之一中的按钮时 mstsc exe 将打开 如果他按下按钮 它将在另一个容器上打开 IE DllImport user32 dll SetL
  • 列表中的“u”是什么意思?

    这是我第一次遇到这种情况 刚刚打印了一个列表 每个元素似乎都有一个u在它前面 即 u hello u hi u hey 它是什么意思 为什么列表的每个元素前面都会有这个 由于我不知道这种情况有多常见 如果您想了解我是如何遇到它的 我会很乐意
  • 为什么这个位图图像在加载后会改变大小?

    快速提问 我有这个1000 1000位图图像 我使用这个例程来加载它 private BitmapSource initialBitmap new BitmapImage new Uri C Users Desktop Original b
  • 如何在VS2005中使用从.bat而不是.exe启动的外部程序进行调试?

    在我的 c 项目的调试属性中 我选择了 启动外部程序 并选择了我希望将调试器附加到的程序的 exe 但是 现在我需要从 bat 文件而不是 exe 启动程序 但 VS2005 似乎不允许这样做 这可能吗 编辑 为了澄清 我需要调试从 bat
  • MPI - 发送和接收列

    我需要从一个进程发送矩阵列并从另一个进程接收它 我尝试运行以下程序 但得到了一个奇怪的结果 至少我这么认为 仅复制矩阵的第一个元素 某些矩阵元素会发生意外变化 include
  • 具有多个父项的 Qt 树模型

    我想构建一棵树 其中一个元素可以引用另一个元素 我想要构建的树是 像这样的东西 A B C D E F P this is a pointer to C D first child of C E second child of C I fo
  • 在一个解决方案中调用不同项目的方法

    1 个解决方案中有 3 个项目 我对第一个项目中的主文件进行的主要操作 但是我需要调用第三个项目中的方法并使用类 例如 第三个项目有 public DataClasses1DataContext base global WindowsFor
  • 使用未命名命名空间而不是静态命名空间

    我可以假设在未命名命名空间中声明的对象相当于static namespace int x 1 static int x 2 FWIK 在这两种情况下 x将具有静态存储期限和内部链接 声明为的对象的所有规则也是如此static适用于未命名名称
  • 为什么存在系统调用

    我一直在阅读有关系统调用及其在 Linux 中如何工作的内容 我还有更多的阅读要做 但我读过的一件事都没有回答 那就是 为什么我们需要系统调用 我知道系统调用是用户空间程序要求内核执行某些操作的请求 但我的问题基本上是 为什么用户空间程序本
  • 异步/等待 - 是*并发*吗?

    我一直在考虑 C 5 中新的异步内容 并且出现了一个特殊问题 据我了解 await关键字是一个简洁的编译器技巧 语法糖来实现连续传递 http en wikipedia org wiki Continuation passing style
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS
  • NHibernate:无状态会话错误消息无法获取代理

    我正在使用 nHibernate 无状态会话来获取对象 更新一个属性并将对象保存回数据库 我不断收到错误消息 无状态会话无法获取代理 我在其他地方有类似的代码 所以我不明白为什么这不起作用 有谁知道问题可能是什么 我正在尝试更新Screen

随机推荐

  • 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 端的方