C ++和Qt:这是内存泄漏吗? (和一般问题)

时间:2011-12-04 14:11:49

标签: c++ qt memory-leaks raii

在过去的两年里,我主要使用C进行编程(以前是一些Java),并决定使用Qt Creator和Qt库来学习C ++。

我的问题是以下代码是否引入了内存泄漏:

    // filename is a QStringListIterator
    // dir is a QDir
    while (filename.hasNext()) {
            QString came_from_file(dir.filePath(filename.next()));
            QFile file(came_from_file);
            file.open(QFile::ReadOnly);
            file.readLine();
            while (!file.atEnd()) {
                    QString line(file.readLine());
                    do_something_with_stuff(line, came_from_file);
            }
    }

具体来说,我不确定生成的dir.filePath(filename.next()) QString会发生什么。它被引用到came_from_file中,或者它的指针在被复制后丢失了吗?它是否被“复制”(我认为它永远不会,直到更改,由于Qt容器的Copy-On-Write性质)?我应该用不同的方式写出来,比如QString match = dir.file...吗?据我了解,这应该是平等的。

它还在Qt文档中说QFile将在析构函数中关闭()文件。析构函数会被调用吗?该变量确实“超出了范围”,但我仍然不确定这是否是所谓的RAII。

如何让file指向其他文件?

如果我将这样的变量传递给函数(我假设这是通过引用,因为函数do_something...以这种方式定义),然后它们超出范围,但是被插入到QHash / QMap /中通过函数QSet,会发生什么?他们被删除了,容器变得疯狂,还是有一些像ref那样花哨的小方案。在这一切背后算吗?或者只是简单地复制了这些值?

我之前已经意识到类似的问题,但我似乎无法通过阅读它们来解释这个问题,因为它们似乎是不同的情况。

如果代码或我的理解有问题,请纠正我。 :)

谢谢, Nanthiel

2 个答案:

答案 0 :(得分:6)

  

具体来说,我不确定生成的dir.filePath(filename.next()) QString会发生什么。

came_from_fileRVO的返回值的副本(除非QDir::filePath开始),而longjmp又是一个自动清理的临时对象。无需将其分配给变量。

  

析构函数是否被调用?变量确实“超出了范围”

当一个对象超出范围时,将调用它的析构函数,除非你使用像QFile这样的不安全结构。

  

如何让file指向其他文件?

我在{{3}}的Qt文档中找不到干净的方法。我建议您为另一个文件声明一个新的QFile。一种可能性,并保持对打开文件数量的控制,是使用范围:

{
    QFile file(some_path);
    // do stuff to file
}   // end of file's scope, so it will be closed

{
    QFile file(other_path);
}   // again, end of scope

OTOH,您可能希望明确关闭QFile,以便在刷新/关闭后检查其状态。

答案 1 :(得分:2)

当您发布的代码留下范围时,将在对象上调用解构器,并清除所有内容。一般来说,在C ++中,唯一需要担心内存泄漏的时候是使用new关键字,或者某个函数返回系统分配对象的指针(如Windows上的设备上下文),在这种情况下你会必须使用适当的系统清理电话。

对于函数,除非指定为引用或指针,否则所有参数都是按值的。引用最常用作函数参数,以防止必须将大对象复制到函数中而导致性能损失。大多数情况下,这些引用都是const,以防止您修改传入的数据的值.C ++中的引用与指针非常相似,没有凌乱的指针语法。

void foo(bar b); //按值

void foo(const bar& b); //由const ref

void foo(bar& b); //通过ref,一个可变的bar对象,此函数对您传入的bar对象执行某些操作,并且该操作的结果将在原始bar对象上可见。