Qt错误地认为QImage已正确加载

时间:2016-05-06 06:58:55

标签: c++ qt memory heap-memory qimage

尝试使用Qt存储一系列图像数据时遇到问题。

以下是一段显示问题的代码:

#include <vector>
#include <iostream>
#include <QImage>

...

const int nFrames = 1000;
std::vector<int> sizes(nFrames);
std::vector<uchar*> images(nFrames);
for (int k = 0; k < nFrames; k++)
{
    QImage *img = new QImage("/.../sample.png");
    uchar *data = img->bits();
    sizes.at(k) = img->width() * img->height();
    images.at(k) = data;
}

std::cout << "Data loaded \"successfully\"." << std::endl;

for (int k = 0; k < nFrames; k++)
{
    std::cout << k << ": " << (int) (images.at(k)[0]) << std::endl;
}

在第一个循环中,程序加载QImage对象并将位图放在images指针向量中。在第二个循环中,我们只读取每个帧的像素。

问题是,即使堆内存已满,程序也会在没有抱怨的情况下继续进行第一个循环。结果,我在第二个循环中崩溃,如程序输出所示:

Data loaded "successfully".
0: 128
1: 128
2: 128
...
192: 128
[crash before hitting 1000]

要重现此问题,您可以使用下面的灰度图像,您可能需要更改nFrames的值,具体取决于您拥有的内存量。

我的问题是:如何以一种允许我检测内存是否已满的方式加载第一个循环中的数据?我不一定需要将QImage对象保留在内存中,而只需要保留images向量的数据。

Sample image

2 个答案:

答案 0 :(得分:1)

首先,第一个循环有内存泄漏,因为img个对象不会被删除。

来自Qt文档:

  

uchar * QImage :: bits()

     

返回指向第一个像素数据的指针。这个   相当于scanLine(0)。

     

请注意,QImage使用隐式数据共享。此功能执行   共享像素数据的深拷贝,从而确保了这个QImage   唯一使用当前返回值的人。

因此,您可以安全地删除循环中的img

    ....
    images.at(k) = data;
    delete img;
}

要检测内存是否已满,您可以检查运营商new是否创建QImage这样的对象:

QImage *img = new QImage("/.../sample.png");
if(!img) {
    //out of memory
}

答案 1 :(得分:0)

部分答案:

第一个循环可以替换为:

for (int k = 0; k < nFrames; k++)
{
    QImage *img = new QImage("/.../sample.png");
    sizes.at(k) = img->width() * img->height();
    uchar *data = new uchar[sizes.at(k)];
    std::copy(img->bits(), img->bits() + sizes.at(k), data);
    images.at(k) = data;
    delete img;
}

这会在images.at(k)中创建img->bits()指向的数据副本。 (顺便说一句,这允许现在删除第一个for循环结束时的QImage。)如果内存不足,则循环中出现std :: bad_alloc错误。

但是,这还不够好。我怀疑将nFrames设置为一个值,使程序所占的最大内存接近极限时(或者当另一个程序在运行时释放内存)。 我担心的是,我仍然不能保证img.bits()会返回指向准确数据的指针。