Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ QDialogs中是否需要析构函数?_C++_Qt_Memory Leaks - Fatal编程技术网

C++ QDialogs中是否需要析构函数?

C++ QDialogs中是否需要析构函数?,c++,qt,memory-leaks,C++,Qt,Memory Leaks,我遵循Qt示例(如),我注意到所有UI项都是作为指针创建的,但我没有看到delete和析构函数 是这样吗?这不会导致内存泄漏吗 我正在尝试添加析构函数 ~TabDialog() { delete tabWidget; delete buttonBox; } 打电话的人 TabDialog *tabDialog = new TabDialog(); tabDialog->setAttribute(Qt::WA_DeleteOnClose); tabDialog->ex

我遵循Qt示例(如),我注意到所有UI项都是作为指针创建的,但我没有看到
delete
和析构函数

是这样吗?这不会导致内存泄漏吗

我正在尝试添加析构函数

~TabDialog()
{
    delete tabWidget;
    delete buttonBox;
}
打电话的人

TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
但是当我关闭对话框时程序崩溃了


析构函数和删除所有指针项是不必要的还是我做错了?

我想你会因为这些行而感到困惑:

tabWidget = new QTabWidget;//and so on
您看不到显式父对象(如
newqtabwidget(this);
),但这里不需要显式父对象。请看这里:

QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setLayout
将重新出租您的
QVBoxLayout
QVBoxLayout
将重新出租其中的所有小部件,因此现在您的小部件有一个父部件,它们将在您的对话框后被销毁

如前所述:

使用布局时,不需要传递父级 构建子窗口小部件。布局将自动重新出租 小部件(使用QWidget::setParent())以便它们是 安装布局的小部件

注意:布局中的小部件是 安装的是布局,而不是布局本身。小部件只能具有 其他小部件作为父部件,而不是布局

Qt上的内存处理 Qt将小部件作为一个树来处理,每个小部件都有一个父部件,每个父部件都有一个
释放子部件内存的义务,如果小部件没有父部件,您应该使用操作员
delete

手动删除它。很抱歉,这不会重现。下面是测试用例。您可能需要添加一些额外的代码以使其重现

Qt的内存管理将处理所有事情,因为所有的小部件最终都有父部件。即:

  • 选项卡在传递到
    addTab
    时即被设置为父级
  • tabWidget
    buttonBox
    一旦添加到布局中,它们就会成为父项
  • 由于您在Qt尝试删除它们之前删除了
    tabWidget
    buttonBox
    ,因此一切正常。一旦删除它们,
    QObject
    的内存管理将被通知,它们将从
    TabDialog
    的子列表中删除。我在析构函数代码中明确了这一点

    Q_ASSERT
    的含义是:“在运行时的这一点上,以下内容必须为真”。如果我们错了,调试生成将中止。因为它不是,所以断言是正确的。因此,在
    delete tabWidget
    之前,该对话框同时具有
    QTabWidget
    QDialogButtonBox
    子项。在
    delete tabWidget
    之后,该对话框不应该再有任何
    QTabWidget
    子项。等等

    #include <QApplication>
    #include <QDialog>
    #include <QTabWidget>
    #include <QDialogButtonBox>
    #include <QVBoxLayout>
    
    class TabDialog : public QDialog
    {
       QTabWidget *tabWidget;
       QDialogButtonBox *buttonBox;
    public:
       TabDialog() :
          tabWidget(new QTabWidget),
          buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok | 
                                         QDialogButtonBox::Cancel))
       {
          tabWidget->addTab(new QWidget, tr("General"));
          tabWidget->addTab(new QWidget, tr("Permissions"));
          tabWidget->addTab(new QWidget, tr("Applications"));
          QVBoxLayout *layout = new QVBoxLayout;
          layout->addWidget(tabWidget);
          layout->addWidget(buttonBox);
          setLayout(layout);
          connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
          connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
       }
       ~TabDialog() {
          Q_ASSERT(findChild<QTabWidget*>());
          Q_ASSERT(findChild<QDialogButtonBox*>());
          delete tabWidget;
          Q_ASSERT(! findChild<QTabWidget*>());
          Q_ASSERT(findChild<QDialogButtonBox*>());
          delete buttonBox;
          Q_ASSERT(! findChild<QTabWidget*>());
          Q_ASSERT(! findChild<QDialogButtonBox*>());
       }
    };
    
    int main(int argc, char *argv[])
    {
       QApplication a(argc, argv);
       TabDialog *tabDialog = new TabDialog();
       tabDialog->setAttribute(Qt::WA_DeleteOnClose);
       tabDialog->exec();
       return 0;
    }
    
    不幸的是,Qt的例子是毫无意义的过早悲观。Qt的类广泛地使用了这个习惯用法。因此,比如说
    QTabWidget
    的大小并不比
    QObject
    的大多少(在我的64位平台上是48字节对16字节)。通过在堆上分配类的固定成员,可以执行两个堆分配:一个小的分配给
    QObject
    派生类,另一个分配给它的PIMPL。你把分配的数量增加了一倍,这是没有充分理由的

    以下是避免这种悲观情绪的方法:

    #include <QApplication>
    #include <QDialog>
    #include <QTabWidget>
    #include <QDialogButtonBox>
    #include <QVBoxLayout>
    
    class TabDialog : public QDialog
    {
       QVBoxLayout m_layout;
       QTabWidget m_tabWidget;
       QDialogButtonBox m_buttonBox;
       QWidget m_generalTab, m_permissionsTab, m_applicationsTab;
    public:
       TabDialog() :
          m_layout(this),
          m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
       {
          m_tabWidget.addTab(&m_generalTab, tr("General"));
          m_tabWidget.addTab(&m_permissionsTab, tr("Permissions"));
          m_tabWidget.addTab(&m_applicationsTab, tr("Applications"));
          m_layout.addWidget(&m_tabWidget);
          m_layout.addWidget(&m_buttonBox);
          connect(&m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
          connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
       }
    };
    
    int main(int argc, char *argv[])
    {
       QApplication app(argc, argv);
       auto tabDialog = new TabDialog();
       tabDialog->setAttribute(Qt::WA_DeleteOnClose);
       tabDialog->show(); // NOT tabDialog->exec()!!
       return app.exec();
    }
    

    如果您构造dialog的小部件并将对话框设置为父级,则不需要在对话框的析构函数中删除它们:Qt将负责删除它们。抱歉,这不会重现。你的代码是正确的。删除是不必要的,但无害的。@KubaOber谢谢,我不确定,因为我希望有一种新+删除模式,而且我不想造成内存泄漏。您确定紧跟在
    tabDialog->exec()
    之后的代码没有试图访问
    tabDialog
    ?请记住,当
    exec()
    返回时,
    tabDialog
    是一个悬空指针。也许你有
    delete tabDialog
    就在它下面,而你却对我们隐藏了它?!
    选项卡dialog->exec()之后没有代码。。。所述函数上没有其他代码,称为
    menu.addAction(showPropertiesAct)在上下文菜单event.is
    tabDialog->setAttribute(Qt::WA_DeleteOnClose)中添加的好主意?还是默认设置?@Thalia当用户关闭对话框时,它将删除该对话框。如果您需要它,并且使用
    tabDialog->show()调用dialog,这是非常好的exec()
    “停止”执行并等待结果,所以您可以编写类似于
    tabDialog->exec()的代码;删除选项卡对话框你的答案有误导性。销毁受Qt内存控制的小部件不是无效的。这里的问题是
    delete
    被传递给悬空指针。Thalia并没有删除现有的小部件——这将是一件非常有效的事情。“Qt”不会删除您已经删除的小部件,这将非常糟糕。Qt实际上跟踪父对象的
    QObject
    s的生命周期,如果您先删除对象,那么Qt的行为非常恰当。同样,这里的错误是,
    delete
    传递的悬空指针不指向有效的
    QObject
    实例,而是指向垃圾!如果您是对的,此代码将无法工作:
    intmain(intargc,char**argv){QApplication应用程序(argc,argv);QWidget w;QVBoxLayout l(&w);QLabel标签(“Hello”);QPushButton按钮(“button”);l.addWidget(&label);l.addWidget(&button);w.show();return app.exec()}
    然而,尽管在退出
    main
    时按顺序执行以下析构函数调用,它仍然可以工作:1<代码>按钮。~QPushButton()
    ,2<代码>标签。~QLabel()
    ,3<代码>l.~QVBoxLayout()
    ,4<代码>w.~QWidget()
    ,5<代码>应用程序~QApplication()。这些调用是C++中的有效C++,BTW. @切尔诺贝利,对象从大多数派生到基类被破坏。代码>选项卡
    #include <QApplication>
    #include <QDialog>
    #include <QTabWidget>
    #include <QDialogButtonBox>
    #include <QVBoxLayout>
    
    class TabDialog : public QDialog
    {
       QVBoxLayout m_layout;
       QTabWidget m_tabWidget;
       QDialogButtonBox m_buttonBox;
       QWidget m_generalTab, m_permissionsTab, m_applicationsTab;
    public:
       TabDialog() :
          m_layout(this),
          m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
       {
          m_tabWidget.addTab(&m_generalTab, tr("General"));
          m_tabWidget.addTab(&m_permissionsTab, tr("Permissions"));
          m_tabWidget.addTab(&m_applicationsTab, tr("Applications"));
          m_layout.addWidget(&m_tabWidget);
          m_layout.addWidget(&m_buttonBox);
          connect(&m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
          connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
       }
    };
    
    int main(int argc, char *argv[])
    {
       QApplication app(argc, argv);
       auto tabDialog = new TabDialog();
       tabDialog->setAttribute(Qt::WA_DeleteOnClose);
       tabDialog->show(); // NOT tabDialog->exec()!!
       return app.exec();
    }
    
    int main(int argc, char *argv[])
    {
       QApplication app(argc, argv);
       TabDialog tabDialog;
       tabDialog.show();
       return app.exec();
    }