0

我一直在潜伏这些问题并学到了很多东西,但最近遇到了一个我不明白的问题。我正在使用 Qt,需要在各种类方法中创建/替换 QMovie 对象(最终在 QLabel 中设置)。我已经使用 new 关键字定义了对象。因此在我的标题中

QMovie * movie;

为简单起见,我将把等效代码放在一个方法中。这相当于两行代码

QMovie * movie = new QMovie(QByteArray1,this);
QMovie * movie = new QMovie(QByteArray2,this);

这可行(我不知道为什么),但由于它是重复操作,我担心内存泄漏。看来第二个定义成功地替换了第一个定义,但是因为大概它们每个都有不同的指针,所以我不知道如何删除指向第一个定义的指针。我在类析构函数中删除了电影,但不知道它是否会删除所有内容。有人知道这里发生了什么吗?

PS我这样做是因为(我在Qt中找到)使用QByteArray(从网上下载)中的数据创建QMovie对象的唯一方法是使用QMovie构造函数。如果我只想用文件中的新数据替换当前电影数据,我可以使用该方法

movie->setFileName(fileName);

但这不是使用二进制数据时的选择。注意:QMovie 也有一个构造函数,它有一个文件名而不是 QByteArray 作为参数。使用文件名也可以使用上面的代码并且更容易测试。

任何帮助将不胜感激。

4

3 回答 3

2

一般来说,如果派生的任何东西QObject都包含在QObjects 的层次结构中,那么当父级被破坏时,它们会自动被破坏。在您的情况下,您QMovie通过构造函数为父级提供,因此应该为您处理清理工作。如果你想确认,从 QMovie 派生一个类,实现一个打印消息的析构函数,并确保它在你期望的时候被调用(即当父级被破坏时)。

于 2012-06-13T01:29:52.973 回答
1

在 C 中这样做的惯用方式是:

  1. 将指针初始化为零。

  2. 在分配给它之前,free()旧指针指向的对象。您不需要检查零:free()在零指针上是安全的无操作。

  3. free()指针超出范围时的对象。

在 Qt 中这样做的惯用方式甚至更简单。

  1. 使用QSharedPointer<>QScopedPointer<>。当它超出范围时,它将自动删除指向的对象。

    • 如果只有一个指针应该拥有该对象,请使用QScopedPointer. 当它超出范围时,它将删除指向的对象。这类似于std::auto_ptr.

    • 对于共享所有权,请使用QSharedPointer. QSharedPointer当指向它的最后一个对象超出范围/被销毁时,它将删除指向的对象。

  2. 对于QScopedPointer,使用reset(T*other)方法为指针分配一个新值。对于QSharedPointer,您只能为其分配其他共享指针,例如QSharedPointer a = QSharedPointer(new Class);

在任何一种情况下,任何先前指向的对象都将被删除。

因此:

class MyClass {
  QScopedPointer<QMovie> movie1;
  QSharedPointer<QMovie> movie2;
public:
  MyClass {} // note: no need for any special initialization
  void method() {
    movie1.reset(new QMovie(...));
    movie2 = QSharedPointer(new QMovie(...));
  }
};

这是完全安全的。您可以MyClass::method()根据需要随时调用,而不会出现内存泄漏。在任何时间点,MyClass 将最多保持两个 QMovie 对象。

于 2012-06-13T02:53:39.040 回答
0
QMovie * movie = new QMovie(QByteArray1,this);
QMovie * movie = new QMovie(QByteArray2,this);

如果这两行在同一个.cc文件中,那么您将收到重新定义错误。如果这两行位于不同的.cc文件中,那么当您构建可执行文件时,您将收到多重定义错误。但是,你的问题有这样的措辞:

我正在使用 Qt,需要在各种类方法中创建/替换 QMovie 对象(最终在 QLabel 中设置)

如果QMovie对象驻留在不同的类中,则不会发生内存泄漏,因为每个类的指针都不同。

但是,如果您的意图是所有类都引用同一个QMovie实例,则需要找到一种方法将实例传递给每个对象。或者,您可以让它们都引用同一个(即,使用单例模式)。

于 2012-06-13T01:29:23.090 回答