QImage:如何正确销毁指向像素数据的指针?

QImage: How to destroy pointer to pixels data properly?

在我控制一个window的主class中,我有这个功能,其中pixmapItem是一个QGraphicsPixmapItem*定义在classheader:

void updateDisplay() {
    uchar *data = new ...; // array of pixel data
    ...
    QImage image = QImage(data, width, height,
                          width, QImage::Format_Indexed8);

    pixmapItem->setPixmap(QPixmap::fromImage(image));
}

我的问题是:当 data 不再需要时,我如何销毁它? "Not needed anymore" 表示上面的函数或我的 class 中的另一个函数将像素图设置为另一个图像。

我看到 QImage 具有可能有用的清理功能,但文档并不清楚如何使用它们以及如何传递要删除的图像的数据指针等参数。

来自 Qt 文档

Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels, data must be 32-bit aligned, and each scanline of data in the image must also be 32-bit aligned.

The buffer must remain valid throughout the life of the QImage. The image does not delete the buffer at destruction.

您需要实现自己的方式来删除该缓冲区

因此您需要自己删除 data,当然诀窍是不要过早删除它——特别是,您不想在 QImage 对象可能仍在使用时删除它它。确保在您的情况下最简单的方法是仅在 QImage 对象被销毁后删除它:

void updateDisplay() {
   uchar *data = new ...; // array of pixel data
   ...
   {
      QImage image = QImage(data, width, height,
                      width, QImage::Format_Indexed8);

      pixmapItem->setPixmap(QPixmap::fromImage(image));
   }
   delete [] data;
}

(注意使用花括号创建内部作用域,从而确保 QImage 对象在 delete [] data 之前从堆栈中弹出并销毁行执行!)

当然,更简单、更安全的方法是完全避免何时删除问题,首先从不手动分配数组。相反,让 QImage 对象分配它自己的数据数组并写入它:

QImage image(width, height, QImage::Format_Indexed8);
char * data = image.bits();
// write into (data) here if you want to, but don't delete [] data, ever!  
// instead, the QImage destructor will do any necessary deletes for you

您可以使用自己的析构函数进行清理class QImage

class NativeBufferQImage : public QImage {
    uchar *data;

    // other stuff

public:
    ~NativeBufferQImage() {
        delete[] this->data; 
    }
};

另请注意,由于 QImage 派生自 QPaintDevice,而 QPaintDevice 有一个 virtual destructor,因此如果某人 delete 您的 NativeBufferQImage通过指向其基数 class(即 QImage)的指针,您的析构函数也将被调用。

QImage销毁后可以删除数据;正如上面的@JeremyFriesner 所示,这可以通过在内部范围内定义 QImage 实例以及在其外部定义 allocate/deallocate 数据来简单地完成。

但是,为什么要费心做这些工作呢?该 QImage 构造函数用于适应复杂的用例,在这些用例中,您已经拥有来自其他来源的像素数据,或者您需要将其保留 "strange" 生命周期。

你的情况反而更简单,像素数据的生命周期与QImage完全相同,所以让它自己为像素分配内存是个更好的主意;这样你就可以确定它的大小和对齐是正确的,并且它是 owned/automatically 被 QImage 实例销毁的;在构建 QImage 对象之后,您可以使用 bits 方法获得一个指向像素数据的指针,并用它做任何您想做的事情。

这样,您的代码将简单地变为:

void updateDisplay() {
    QImage image = QImage(width, height,
                          width, QImage::Format_Indexed8);
    uchar *data = image.bits();
    ... 

    pixmapItem->setPixmap(QPixmap::fromImage(image));
}

更简单、更安全且内存泄漏风险为零。

最好的办法就是不做:

void updateDisplay() {
    QImage image(width, height, QImage::Format_Indexed8);
    auto const data = image.bits();
    // you can modify the data here
    pixmapItem->setPixmap(QPixmap::fromImage(image));
}