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);
}
imageLabel
和scrollArea
分别是QLabel
和QScrollArea
的指针成员。
我知道在scrollArea->setWidget(imageLabel);
行中,滚动区域拥有imageLabel指针的所有权,并在需要时将其删除。对于setCentralWidget(scrollArea);
来说,该窗口也拥有scrollArea的所有权。
但是,在构建过程中,如果imageLabel
创建成功,但是scrollArea
创建失败,imageLabel
不会泄漏吗?
如果是,解决此问题的规范方法是什么?
答案 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”,当这种情况出现时,您几乎无法采取任何措施来保护您的应用程序。好消息是,我们大多数人在正常情况下从未遇到过这种情况。