数组中未映射的内存访问从python传递到c++
unmapped memory access in array passed from python to c++
我正在使用pybind11
向python公开一个C++类。
它在构造函数中获取一个numpy.array
,并获取一个指向其内部数据的指针。(它不复制数据(。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <iostream>
namespace py = pybind11;
struct Data
{
Data(const py::array_t<double, py::array::c_style| py::array::forcecast>& arr)
: p(arr.data())
{
std::cout << "arr=" << p << std::endl;
std::cout << "[0]=" << p[0] << std::endl;
}
const double* p;
};
我有另一个类,它接受const Data&
,从而获得对数组数据的访问权限。
struct Manager
{
Manager(const Data& data)
: data_(data)
{
const double* p = data_.p;
std::cout << "data.arr=" << p << std::endl;
std::cout << "data.[0]=" << p[0] << std::endl;
}
const Data& data_;
};
在这里,这两个类使用pybind11:向python公开
PYBIND11_MODULE(foo, m)
{
py::class_<Data>(m, "Data")
.def(py::init<const py::array_t<double, py::array::c_style| py::array::forcecast>&>());
py::class_<Manager>(m, "Manager")
.def(py::init<const Data&>());
}
这很有效。我可以导入我的模块,从numpy.array
创建一个Data
实例,然后将其传递给Manager
:
>>> import pandas
>>> import numpy
>>> import foo
>>> df = pandas.DataFrame(data = numpy.random.rand(990000, 7))
>>> d = foo.Data(df.values)
>>> c = foo.Manager(d)
我的脚本运行良好,您可以看到我的C++代码访问numpy.array
数据,并将其地址和第一个元素打印到stdout:
arr=0x7f47df313010
[0]=0.980507
data.arr=0x7f47df313010
data.[0]=0.980507
以上所有内容我都是为了创建一个MCVE来说明我在下面遇到的问题。
然而,现在,我加载了一个pandas DataFrame pickle文件,我有这个文件(这里是有问题的pickle的下载链接(:
>>> import pandas
>>> import foo
>>> df = pandas.read_pickle('data5.pk')
>>> a = df.values
>>> d = foo.Data(a)
>>> c = foo.Manager(d)
并且我的C++代码在试图访问数组数据时崩溃。
这是标准输出:
arr=0x7f8864241010
arr[0]=7440.7
data.arr=0x7f8864241010
<dumps core>
因此,指向数组的指针在Manager
中是相同的,但试图取消引用指针会导致SEGV。
通过valgrind运行它,valgrind报告Access not within mapped region at address 0x7f8864241010
(即:numpy.array
的地址(。
Python对我的pickle文件非常满意:
>>> import pandas
>>> df = pandas.read_pickle('data5.pk')
>>> df.shape
D_11(990000, 7)
我一辈子都无法弄清楚我的pickle文件出了什么问题。
- 我试过创建一个
numpy.array
和酸洗,效果很好 - 我试过制作
pandas.DataFrame
和酸洗,效果很好 - 我已经将我的"无效"数据帧切片,我可以得到一个工作正常的子集
python对我的数据中的某些内容感到满意,但在C++中会导致SEGV。
我该如何诊断?
泡菜很好。是你的代码错了。您获取一个指向数组数据的指针,而不做任何事情来确保该数据实际上与使用它的对象一样长
您需要保留对数组的引用,并执行相关的refcount管理。pybind11可能有某种机制来表示Python引用并为您处理引用计数。快速查看文档,您的代码可能应该按值取array_t
,而不是const引用(因为array_t
已经表示Python引用(,并将其存储到array_t
实例变量中。
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- Pybind11:将元组列表从Python传递到C++
- 如何在c++中使用引用实现类似python的行为
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 递归列出所有目录中的C++与Python与Ruby的性能
- IPC使用多个管道和分支进程来运行Python程序
- 从python中调用C++函数并获取返回值
- Python 3.7 和 excess_args 的 SWIG 问题
- Python中的for循环与C++有何不同
- 使用Pybind11向Python公开Eigen::张量
- Python str to C++ to Python str
- 如何使用Python从C++中读取谷物序列化数据
- 如何在C++中使用pybind11加载一个pickle python列表
- 如何在c++中使用system()来运行包含空格的python脚本
- python集合的C++等价物是什么.计数器
- 如果C++对象的类在另一个boost模块中声明,如何使用boost将指向该对象的指针返回到python
- 从python调用openMP共享库时,未定义opnMP函数
- 使用JsonCpp将数据返回到带有pybind11的python会在python调用中产生Symbol not foun
- 如何将真正的字符串从python c-api转换为python脚本
- Python ctype 'c_char_p' Memory Leak