QT Image Viewer示例,是否可能发生内存泄漏?

时间:2019-02-13 09:13:48

标签: c++ qt

QT文档网站上的Image Viewer Example包含以下代码段:

ImageViewer::ImageViewer()
   : imageLabel(new QLabel)
   , scrollArea(new QScrollArea)
   , scaleFactor(1)
{
   imageLabel->setBackgroundRole(QPalette::Base);
   imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
   imageLabel->setScaledContents(true);

   scrollArea->setBackgroundRole(QPalette::Dark);
   scrollArea->setWidget(imageLabel);
   scrollArea->setVisible(false);
   setCentralWidget(scrollArea);

   createActions();

   resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
}

imageLabelscrollArea分别是QLabelQScrollArea的指针成员。

我知道在scrollArea->setWidget(imageLabel);行中,滚动区域拥有imageLabel指针的所有权,并在需要时将其删除。对于setCentralWidget(scrollArea);来说,该窗口也拥有scrollArea的所有权。

但是,在构建过程中,如果imageLabel创建成功,但是scrollArea创建失败,imageLabel不会泄漏吗?

如果是,解决此问题的规范方法是什么?

3 个答案:

答案 0 :(得分:1)

我认为可以采用两种方法:

1 。使用智能指针而不是原始指针(例如QPointer)。

    class ImageViewer : public QMainWindow
    {
       QPointer<QLabel> imageLabel;
       QPointer<QScrollArea> scrollArea;
    };

在这种情况下,如果imageLabel的构造函数(或scrollArea构造函数的主体抛出异常),将调用ImageViewer的析构函数

2 。将内存分配移到构造函数的主体内,并用try / catch块进行包装。

    ImageViewer::ImageViewer()
        : imageLabel(nullptr)
        , scrollArea(nullptr)
        , scaleFactor(1)
    {
        try {
            imageLabel = new QLabel();
            scrollArea = new QScrollArea();
        } catch (std::bad_alloc&) {
            delete imageLabel;
            delete scrollAreal;
        }
        // ...
    }

可能会找到更多详细信息here道德#4 与您的问题有关)

答案 1 :(得分:0)

暂时解决了这个问题:

ImageViewer::ImageViewer()
    : scaleFactor(1)
{
   //Manage pointers with unique_ptr until it's time to transfer ownership. 
   auto uniqueImageLabel = std::make_unique<QLabel>();
   auto uniqueScrollArea = std::make_unique<QScrollArea>();

   //Copy pointers to members for access as per normal.
   imageLabel = uniqueImageLabel.get();
   scrollArea = uniqueScrollArea.get(); 

   imageLabel->setBackgroundRole(QPalette::Base);
   imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
   imageLabel->setScaledContents(true);

   scrollArea->setBackgroundRole(QPalette::Dark);
   //ScrollArea now takes ownership of image label. 
   scrollArea->setWidget(uniqueImageLabel.release());
   scrollArea->setVisible(false);
   //Window now takes ownership of scroll area.
   setCentralWidget(uniqueScrollArea.release());

   createActions();

   resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
}

答案 2 :(得分:0)

嗯,这可能是 Qt 的整体问题,因为它不是完全异常安全的https://doc.qt.io/qt-5/exceptionsafety.html

从实用的角度来看,除非您创建任务关键型应用,否则这无关紧要。如果滚动区域的构建(即动态分配)失败,那么这意味着发生了一些非常糟糕的事情:您的所有内存都已耗尽,甚至没有将内存交换到磁盘有助于解决它。在这种情况下,一些内存泄漏是您最不关心的。无论如何,您可能会崩溃或完全冻结您的计算机,因此需要重新启动。

当然,您可以尝试使用智能指针解决部分代码,但它仍然可能在 Qt 库本身内部留下大量泄漏。如果您的内存完全耗尽,您的程序无论如何都会出现故障。

因此,除非您创建真正防弹的关键任务应用程序,否则您可能不需要关心这种情况。如果我是你,我会更关心系统内存泄漏,即你在正常情况下忘记释放内存。

除非您创建任务关键型应用,否则您无需担心内存不足。这是一个“vis maior”,当这种情况出现时,您几乎无法采取任何措施来保护您的应用程序。好消息是,我们大多数人在正常情况下从未遇到过这种情况。