我想快速把从一个点云bin文件里读取的十几万或者几十万个点的数据(每个点有(x,y,z,i)四个float类型的值)以字节形式从文件里读取出来后,快速赋值给一个用std::vector<std::vector<float>>实现的二维数组,用memcpy()拷贝字节数据到这个二位数组data()指向的地址,发现这样作后在后面读取这个数组的数据时总是发生segment fault错误而崩溃。
网上搜了很久没找到类似的问题,找资料重新琢磨了一下vector存储数据的内存结构组织形式,发现,当vector嵌套有多维时,其全部数据并不是线性顺序存放的(这和我们平时熟悉的NVIDIA CUDA实现多维数组的线性化存储是不一样),例如说二维时,第一维的数组的每个element的地址里存放的是这个element对应的子数组的首地址(但不是子数组的数据内容存储地址!),就好比指向指针的指针,所以赋值时不能一次借助memcpy()给这种在存储上并不连续的二维数组赋值,需要在第一维度的数组上进行循环,获取每个子数组的地址,再使用memcpy()给每个字数组拷贝赋值,这样才是正确的赋值方式。给出代码实例:
int data_length = 0;
char *data = nullptr;
int ret = read_binary_file(pc_file, &data, &data_length);
if (ret != 0) {
std::cout <<"failed to read point cloud " << pc_file << std::endl;
return -1;
}
float* fdata = reinterpret_cast<float*>(data);
int point_num = data_length/16;
std::vector<std::vector<float>> points(point_num, std::vector<float>(4, -100));
// 这样赋值会导致后面读取数据时崩溃
// memcpy(points.data(), fdata, data_length);
for (int i=0; i < point_num; i++) {
memcpy(points[i].data(), fdata+ 4*i, 16);
//也可以下面这样赋值,子数组地址一定要使用第一个元素的地址!!! 使用&points[i]也是错的!
// &points[i]是字数组的首地址但是不是存放数据的地址!需要使用data()获取或使用其第一元素的地址
// memcpy(&points[i][0], fdata+ 4*i, 16);
}
delete fdata;
//读取数据进行voxelization处理
...