Qt:使用“new without delete”会导致控件内存泄漏吗?

20

我在查看Qt示例这里

在构造函数内部,他们有:

 Window::Window()
 {
     editor = new QTextEdit();   // Memory leak?
     QPushButton *sendButton = new QPushButton(tr("&Send message")); // Memory leak?

     connect(sendButton, SIGNAL(clicked()), this, SLOT(sendMessage()));

     QHBoxLayout *buttonLayout = new QHBoxLayout();  // Memory leak?
     buttonLayout->addStretch();
     buttonLayout->addWidget(sendButton);
     buttonLayout->addStretch();

     QVBoxLayout *layout = new QVBoxLayout(this);    // Memory leak?
     layout->addWidget(editor);
     layout->addLayout(buttonLayout);

     setWindowTitle(tr("Custom Type Sending"));
 }

那些带有注释的代码行

// Memory leak?

这些不是内存泄漏吗?

如果是的话,由于Window类没有构造函数,我应该将所有这些变量(editor已经是)作为Window的成员变量吗?

或者... Qt在超出作用域时会内部“删除”这些成员变量吗?

5个回答

30
不会,addWidget()函数将保留小部件的所有权。然后它将销毁它所拥有的小部件。
此外,您可以在这里阅读到:
引用:

与QObjects一样,QWidgets可以使用父对象创建,以指示所有权,确保在不再使用对象时删除它们。对于小部件,这些父子关系具有其他含义:每个子小部件都显示在其父小部件占用的屏幕区域内。这意味着当您删除窗口小部件时,它包含的所有子小部件也将被删除。


11
如果在 new 和 addWidget 之间抛出异常,那么会出现内存泄漏。否则,父控件将拥有该内存空间的所有权。
QHBoxLayout *buttonLayout = new QHBoxLayout();  // Memory leak?
//make sure you don't throw here
buttonLayout->addWidget(sendButton);

6
除了Klaim的正确答案外:
我建议将这些指针存储在std::auto_ptr中,同时将它们传递给它们的父级。
std::auto_ptr<QHBoxLayout> buttonLayout( new QHBoxLayout() );
// make things which could throw...
layout->addLayout(buttonLayout.release());

这样做可以确保您不会出现泄漏问题。

比我的答案还要好。 - Marcel Gosselin
如果这样做,它不会被双重删除吗?一次是由auto_ptr,然后再次由QObject? - James
@James 调用 release() 会使智能指针释放其所有权,因此它将不再删除对象。但是,如果您调用 get(),则会获得一个指针,但智能指针仍保留所有权。 - Klaim

2
从C++14开始,您可以使用std::make_unique()方便函数模板来创建一个具有小部件独占所有权的std::unique_ptr<>。然后,在将小部件传递给addLayout()时,通过调用release()使智能指针放弃所有权:
auto buttonLayout = std::make_unique<QHBoxLayout>(); 
// ...
// an exception could be thrown here
// ...
layout->addLayout(buttonLayout.release());

0

由于.release()的调用,它不会被重复删除。

请注意,std::unique_ptr正在取代std::auto_ptr。希望QT将支持移动语义,那么release()将被替换为layout->addLayout(std::move(buttonLayout)),如果没有调用移动,则会出现编译错误。


1
它是shared_ptr取代了auto_ptr,unique_ptr仅用于scoped ptrs而不是共享,话虽如此,它非常适合这项工作,因为我们不想分享它。 - Niklas Schnelle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接