繁体   English   中英

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

[英]QImage: How to destroy pointer to pixels data properly?

在控制窗口的主类中,我具有以下功能,其中pixmapItem是在类头中定义的QGraphicsPixmapItem*

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时销毁data “不再需要”表示上面的函数或类中的另一个函数将像素图设置为另一个图像。

我已经看到QImage具有清理功能,该功能可能会有所帮助,但是关于如何使用它们以及如何传递参数(例如要删除的图像数据指针)的文档尚不清楚。

QImage被销毁时,您可以删除数据。 如上面的@JeremyFriesner所示,可以通过在内部范围内定义QImage实例并在其外部分配/取消分配数据来简单地完成此操作。

但是,为什么还要烦恼所有这些工作呢? QImage构造函数可以适应复杂的用例,在这些用例中您已经具有来自其他来源的像素数据,或者需要在“奇怪的”生命周期内保留它。

相反,您的情况更简单,像素数据的寿命与QImage完全相同,因此最好让它自己为像素分配内存; 这样,您可以确定它的大小和对齐方式正确,并且由QImage实例拥有/自动销毁; 构造完QImage对象后,您可以使用bits方法使用一个指向像素数据的指针,并对其进行任何操作。

这样,您的代码将变成:

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

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

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

从Qt文档

构造具有给定宽度,高度和格式的图像,该图像使用现有的内存缓冲区数据。 宽度和高度必须以像素为单位指定,数据必须是32位对齐的,并且图像中数据的每条扫描线也必须是32位对齐的。

缓冲区必须在QImage的整个生命周期内保持有效。 映像不会删除销毁的缓冲区。

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

因此,您需要自己删除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;
}

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

当然,更简单,更安全的方法是完全不必首先删除数组,从而避免了何时删除的问题。 相反,让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

您可以使用自己的析构函数对QImage进行子类化,以进行清理。

class NativeBufferQImage : public QImage {
    uchar *data;

    // other stuff

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

还要注意,由于QImage是从QPaintDevice派生的,并且QPaintDevice具有虚拟析构函数 ,因此,如果有人通过指向其基类的指针(即QImagedelete NativeBufferQImage ,那么也会调用您的析构函数。

最好的方法是不要这样做:

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));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM