You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++读取MNIST时array、cv::Mat、vector的sizeof差异及函数返回异常问题

问题描述

我正在尝试读取MNIST文件,并将元素存入存储matrix的vector中,可参考公开的MNIST读取代码实现。

我的代码片段如下:

for(int r = 0; r < n_rows; ++r)
{
    for(int c = 0; c < n_cols; ++c)
    {
        unsigned char temp = 0;
        file.read((char*)&temp, sizeof(temp));
        data[r][c] = temp;
        //std::cout << "r: " << r << " c: " << c << " temp: "<< sizeof(temp) << "\n";
    }
} // 此处打印数组输出正常

for(int k = 0; k < 28; k++)
{
    for(int z = 0; z < 28; z++)
    {
        std::cout << data[k][z] << " ";
        if(z == 27)
            std::cout << "\n";
    }
}

cv::Mat img(28,28,CV_8U,&data);
mnist.push_back(img);
std::cout<<"data: "<< sizeof(data) << " img: "<< sizeof(img) << " mnist: " << sizeof(mnist) <<"\n";

上述代码最后一行的输出如下:

data(array): 784 img(cv::Mat): 96 mnist(vector of matrix): 24

它们的大小难道不应该至少一致吗?我认为这就是打印matrix时无法得到和array相同的正确输出的原因。我猜测vector引用了matrix,而matrix又引用了array,后续内存某处发生了修改,导致输出不符合预期?

补充说明

上述代码写在一个返回matrix vector的函数中。
如果我把这段代码直接写在main函数里,输出就是正常的!
有没有人可以解释这个问题?我更希望把这段逻辑拆到独立函数中,而不是让main函数过于臃肿,不过目前我还是先使用可以正常运行的写法。


问题解答

1. sizeof输出差异的原因

你观察到的sizeof输出差异是完全正常的,sizeof是编译期运算符,返回的是变量对应类型本身占用的栈内存大小,不会统计其内部指针指向的堆内存数据体积:

  • data是28*28的unsigned char栈数组,类型本身固定占784字节,所以sizeof返回784
  • cv::Mat是封装了图像数据指针、尺寸、通道数等信息的类,64位系统下该类的实例本身固定占96字节,实际的像素数据存储在堆上,不会被计入sizeof结果
  • std::vector本身仅保存三个管理内存的指针,64位系统下固定占24字节,内部存储的所有元素都存在堆上,也不会被sizeof统计

2. 函数运行异常、main运行正常的原因

你使用的cv::Mat img(28,28,CV_8U,&data);构造函数采用零拷贝引用逻辑:Mat不会复制data数组中的像素值,仅会保存指向data数组内存的指针。
如果这段代码写在独立函数中,data是函数的局部栈变量,函数执行结束返回后,栈内存会被系统自动回收,此时vector中存储的Mat持有的就是野指针,访问时会读到乱码,甚至触发崩溃。
而代码写在main函数中时,data的生命周期和整个程序运行周期一致,Mat引用的内存始终有效,所以运行正常。

3. 拆分到独立函数的解决方案

创建Mat时强制做一次数据拷贝即可,修改构造语句为:

cv::Mat img(28,28,CV_8U, &data).clone();

clone()方法会把data里的像素值拷贝到Mat自行管理的堆内存中,和原来的data数组完全解绑,就算函数执行完data被释放,Mat里的数据也不会受影响。


内容的提问来源于stack exchange,提问作者Pat cm pro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:12:00