QStandardItemModel内存管理

    参考资料[2]已经对如何结合QTreeViewQStandardItemModel创建一个树形结构做了很详细的说明,本文不再赘言。本文的主要目的是描述在编程过程中遇到的问题。

1 问题   

     在参考资料[2]中,为QStandardItemModel添加Item时,使用到下面的代码片段:

QList<QStandardItem *> items; 
for (int i = 0; i < 3; ++i) 
{ 
	QStandardItem *item = new QStandardItem(QString("item %0").arg(i));

	if (0 == i) 
		item->setCheckable(true); 
	items.push_back(item); 
} 
goodsModel->appendRow(items);

    从上述的代码中可见,每创建一个item,就需要使用new分配一次内存。(1)那么,在销毁QStandardItemModel的对象之前,是不是需要使用delete先将其各个item所占用的内存释放掉呢?正如参考资料[6]所提出的疑问那样。(2)另外,参考资料[8]也提出疑问,调用 clear()之后是否会释放QStandardItemModel所有Item的内存呢?(3)调用remoeRow()删除一行时,是否也会同时释放这一行所占用的内存呢?

2 实验

    根据参考资料[7]的指出,QStandardItemModel会获取Item的所有权,因此在销毁时同时释放各个Item的内存, 然而View并没有获取QStandardItemModel的所有权(因为同一个Model可以被多个View使用),因此需要程序员手工释放QStandardItemModel对象内存;参考资料[8]则指出,当调用clear()之后,所有item的内存都会被释放。

    上述的说法是否正确呢?下面做一个测试。

    根据参考资料[2]创建一个棵简单的树

<pre name="code" class="cpp">MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    goodsModel = new QStandardItemModel(0, 3, this);

    ui->treeView->setColumnWidth(0, 50);
    ui->treeView->setColumnWidth(1, 200);
    ui->treeView->setColumnWidth(2, 200);
    ui->treeView->setColumnWidth(3, 200);
    goodsModel->setHeaderData(0, Qt::Horizontal, tr("No"));
    goodsModel->setHeaderData(1, Qt::Horizontal, tr("name"));
    goodsModel->setHeaderData(2, Qt::Horizontal, tr("value1"));
    ui->treeView->setModel( goodsModel );


    QList<QStandardItem *> items;

    for (int i = 0; i < 3; ++i) {
            QStandardItem *item = new QStandardItem(QString("item %0").arg(i));
            if (0 == i)
                item->setCheckable(true);
            items.push_back( item );
    }
    goodsModel->appendRow( items );

    // 释放Items内存
    // delete goodsModel; 
    // goodsModel = NULL;        // 避免在析构函数中再次释放内存
    // goodsModel->removeRow(0); // 删除第0行
    // goodsModel->clear();      // 清空Model

    // 尝试访问Items的内存
    for (int i = 0; i < items.length(); i++) {
        qDebug() << items.at(i)->column();
    }
}
     效果如下图(证明创建树成功): 

                             图 1

    若是将上述代码中下述语句的前面两行或者第3第4行的其中一行

    // 释放Items内存
    // delete goodsModel; 
    // goodsModel = NULL;        // 避免在析构函数中再次释放内存
    // goodsModel->removeRow(0); // 删除第0行
    // goodsModel->clear();      // 清空Model

   这时候再编译运行则提示:

程序异常结束。

    出现这个异常,主要是因为delete goodsModel,removeRow(0)或者clear()都会导致Moel释放Item的内存,下面语句尝试继续访问Item的内存时,产生非法内存访问

    // 尝试访问Items的内存
    for (int i = 0; i < items.length(); i++) {
        qDebug() << items.at(i)->column();
    }
    如果将上面的代码片段注释掉,则不会出现 程序异常结束的情况,但是所创建的树是空的


                     图 2 goodsModel->removeRow(0)的结果



                图3 goodsModel->clear() / delete goodsModel的结果

    上述实验验证了参考资料[7][8]的说法是正确的。同时也回答了第1章的第3个问题:removeRow()也会导致内存的释放。

    然而,正如参考资料[8]所指出的那样,QList是不会自动释放添加到其中的指针变量的(详细释放方法见参考资料[11]),唯有将各个Item添加到QStandardItemModel之后,QStandardItemModel才为它们管理内存。

参考资料

[1]QT中树控件QTreeView开发实例

[2]Qt TreeView

[3]Qt中如何自定义ListView/TreeView单个item的显示和响应

[5]Qt树形控件QTreeView使用1——节点的添加删除操作 复选框的设置

[6]Qt: Does this constitute a memory leak or not?

[7]Memory Management in Qt

[8]QStandardItemModel with QStandardItem usage

[9]Qt: QStandardItemModel的极品提示

[10]QStandardItemModel角色控制及QTreeView添加不同的右键菜单

[11]QList类介绍以及QList的内存释放

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneSea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值