QScopedPointer介紹
QScopedPointer
就分配空間和釋放空間而言,Qt的處理有點乏味,要不然是通過隱式共享的containers,要不然就是通過QObject的父子關系模式。但總有些時候我們需要在堆上分配一些空間,問題來了,我們該在哪里delete它,如何能夠確保不產生內存泄露呢?
QScopedPointer就為了解決這個問題而生的,哈哈
QScopedPointer在其生命期結束后會自動刪除它所指的對象。
- void foo()
- {
- QScopedPointer<int> i(new int(42));
- …
- if (someCondition)
- return; // 我們在堆上構造的整數這時會在這里刪除或者是在下面
- …
- } // … 也可能在這里
復制代碼
這樣就可以確保我們在堆上為整數42分配的空間不會產生內存泄露,同時我們也不用手動delete它,哈哈。
那我們如何訪問QScopedPointer 所指的對象呢?QScopedPointer重新實現了operator* 和operator->,因此我們可以像下面這樣使用它:
- QScopedPointer<int> i(new int(42));
- *i = 43;
復制代碼
有些運算符是不支持的,如賦值運算符:
- QScopedPointer<int> i(new int(42));
- i = new int(43); // 編譯不通過
- i.reset(new int(43)); // 正確
復制代碼
operator T*()也是沒有的:
- int *foo()
- {
- QScopedPointer<int> i(new int(42));
- …
- return i; // thankfully, this does not compile.
- }
復制代碼
看到錯誤沒?在上面的代碼中一旦我們return,我們構造的對象將被刪除因為i的生命期已經結束,我們將會返回一個野指針,這可能會導致崩潰。如果真要返回我們應該像下面這樣:
- int *foo()
- {
- QScopedPointer<int> i(new int(42));
- …
- if (someError)
- return 0; // our integer is deleted here
- return i.take(); // from now on, our heap object is on its own.
- }
復制代碼
通過調用take()方法,我們告訴QScopedPointer它的工作已經做完,現在由我們來接管在堆上分配對象的所有權,哈哈
上面的只是針對new而言的,那么如果是malloc或者operator new[]構造數組呢?這里我們需要使用QScopedPointer的第二個參數:
- QScopedPointer<int, QScopedPointerPodDeleter> pod(static_cast<int *>(malloc(sizeof int)));
復制代碼
但QScopedPointer生命期結束后QScopedPointerPodDeleter (pod 是 “plain old data”的縮寫) 會調用free來釋放我們分配的空間。
為了方便我們有一個專門針對數組的類,QScopedArrayPointer,在其生命期結束后會自動調用delete[]方法:
- void foo()
- {
- QScopedArrayPointer<int> i(new int[10]);
- i[2] = 42;
- …
- return; // our integer array is now deleted using delete[]
- }
復制代碼
注意如果你有一個引用計數的對象,可以使用QExplicitlySharedDataPointer來確保當其引用計數為0時正確刪除。
在 Qt的S60分支中,QScopedPointe 和QExplicitlySharedDataPointer已經得到了廣泛的使用。相信不久就可以加入Qt的總分支中。通過使用Qt的這些智能指針,我 們可以讓我們的程序更易讀同時也不用過于擔心,因為這些方法都是inline內聯的。
經常這么用
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.
};