Qt中的智能指针

来源:互联网 发布:闪电网络 中转交易 编辑:程序博客网 时间:2024/06/06 00:31

尽管C++不支持垃圾回收,但C++对象的自动内存管理还是可以通过好几种方式来实现,主要是通过智能指针使用以及引用计数。Qt提供了许多不同的智能指针类型,以适用于不同的用途。

一个重写了指针解引用操作operator*()和operator->()的类被称为智能指针。这使得类实例的行为就像它是一个内置指针一样。这样的类几乎总是模板类,因此定义时必须在模板参数中提供引用类型。最常见的能找到这些重写操作算子的地方是在迭代器以及智能指针中。使它们变得智能的通常是在构造、析构以及赋值中的自定义行为。

QScopedPointer是一个在指针作用于结束后自动删除所引用对象的智能指针。它类似于std::auto_ptr。复制QScopedPointer是毫无意义的,因为它会导致所引用的对象重复删除。指针的作用域指针的作用域明确地表明了所引用对象的生存期和所属。

类似于QScopedPointer,QSharedPointer是一个自动删除它所引用的对象的智能指针,但是它允许被复制,而且QSharedPointer会保持一个引用计数。共享的堆对象只有在最后一个指向它的智能指针销毁时才会被删除。


一、QScopedPointer

QScopedPointer类存储了一个指向动态分配对象的指针,一旦析构就会被删除。

手动管理对分配的对象是困难的并且容易出错的,通常会导致内存泄漏并且难于维护。QScopedPointer是一个小型工具类,它通过赋予基于栈内存的所有权给堆分配,大大简化了上述操作,更一般的被称为资源获取时初始化(RAII)。

QScopedPointer保证超出当前作用域时指向的对象会被删除。

考虑这个执行堆分配、有不同出口点的函数:

void myFunction(bool useSubClass)  {      MyClass *p = useSubClass ? new MyClass() : new MySubClass;      QIODevice *device = handsOverOwnership();        if (m_value > 3) {          delete p;          delete device;          return;      }        try {          process(device);      }      catch (...) {          delete p;          delete device;          throw;      }        delete p;      delete device;  } 

手动使用delete调用简直就是累赘。使用QScopedPointer,代码可以简化为:

void myFunction(bool useSubClass)  {      // assuming that MyClass has a virtual destructor      QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);      QScopedPointer<QIODevice> device(handsOverOwnership());        if (m_value > 3)          return;        process(device);  } 

QScopedPointer有意地没有实现拷贝构造函数和赋值操作符,这样所属和生命周期才相通。


在常规C++指针上的常量限制也可以使用QScopedPointer表示:

    const QWidget *const p = new QWidget();      // is equivalent to:      const QScopedPointer<const QWidget> p(new QWidget());          QWidget *const p = new QWidget();      // is equivalent to:      const QScopedPointer<QWidget> p(new QWidget());          const QWidget *p = new QWidget();      // is equivalent to:      QScopedPointer<const QWidget> p(new QWidget()); 
自定义清理处理函数

数组以及使用malloc分配的指针一定不能使用delete删除。

QScopedPointer的第二个模板参数可以用于自定义清理处理函数。

存在以下自定义清理处理函数:

1)QScopedPointerDeleter——默认,使用delete删除指针。

2)QScopedPointerArrayDeleter——使用delete []删除指针。这个处理函数用于使用new []分配的指针。

3)QScopedPointerPodDeleter——使用free()删除指针。这个处理函数用于使用malloc()分配的指针。

4)QScopedPointerDeleteLater——通过调用deleteLater()删除指针。这个处理函数用于指向活跃于QLoopEvent中的QObject对象的指针。


你可以传递自己的类作为处理函数,只要这些类有公有的静态函数 void cleanup(T* pointer)。

// this QScopedPointer deletes its data using the delete[] operator:  QScopedPointer<int, QScopedPointerArrayDeleter<int> > arrayPointer(new int[42]);    // this QScopedPointer frees its data using free():  QScopedPointer<int, QScopedPointerPodDeleter> podPointer(reinterpret_cast<int *>(malloc(42)));    // this struct calls "myCustomDeallocator" to delete the pointer  struct ScopedPointerCustomDeleter  {      static inline void cleanup(MyCustomClass *pointer)<span style="white-space:pre">  </span>// 这个不是公有的吧      {          myCustomDeallocator(pointer);      }  };    // QScopedPointer using a custom deleter:  QScopedPointer<MyCustomClass, ScopedPointerCustomDeleter> customPointer(new MyCustomClass

前向声明指针


前向声明的类可以用于QScopedPointer,只要当QScopedPointer需要清理时前向声明类的析构函数可用就行。

具体来说,这意味着所有包含指向一个前向声明类的QScopedPointer类的那些类必须有非内联的构造函数、析构函数和赋值运算符:

class MyPrivateClass; // forward declare MyPrivateClass    class MyClass  {  private:      QScopedPointer<MyPrivateClass> privatePtr; // QScopedPointer to forward declared class    public:      MyClass(); // OK      inline ~MyClass() {} // VIOLATION - Destructor must not be inline    private:      Q_DISABLE_COPY(MyClass) // OK - copy constructor and assignment operators                               // are now disabled, so the compiler won't implicitely                               // generate them.  };  
否则,编译器会输出”无法析构MyPrivateClass“的警告。

0 0
原创粉丝点击