簡介
Qt提供了很多智能指標,比較常見的有QPointer, QSharedDataPointer ,QSharedPointer,QWeakPointer和QScopedPointer。
描述
QPointer (4.0) 已經過時,可以被QWeakPointer所替代,它不是安全執行緒的。
QSharedDataPointer (4.0) 提供對資料的COPY-ON-WRITE以及淺拷貝,提供對資料線程安
全的保護。(註:提供對資料的安全執行緒保護要結合QsharedData來完成),它是安全執行緒的。
QSharedPointer (4.5) 實現了引用計數的可共用資源的強型別指標,它是安全執行緒的。有著與std::auto_ptr類似的特性,而最大的區別在於它不能轉讓所有權而auto_ptr可以。
QWeakPointer (4.5) 實現了引用計數的可共用資源的弱類型指標,它是安全執行緒的。
QScopedPointer (4.6) 實現了非引用計數的獨享資源的強型別指標,它是安全執行緒的。
strong pointer : 在有它所指向的資源的所有權期間,永遠不會放棄這個所有權。
weak pointer:在有它所指向的資源的所有權期間,允許外界釋放其資源從而使其放棄這個所有權。
詳解
QScopedPointer 與 std::unique_ptr
它們概念上應當是是一樣的。下面不再區分:
這是一個很類似auto_ptr的智能指標,它封裝了new操縱符在堆上指派的動態對象,包管動態建立的對象在任何時候可以被正確地刪除。但它的所有權加倍嚴格,一旦擷取了對象的經管權,你就無法再從它那邊取回來。
無論QScopedPointer 還是 std::unique_ptr 都擁有一個很好的名字,它向代碼的瀏覽者傳遞了明白的資訊:這個智能指標只能在本感化域裡應用,不能被轉讓。因為它的拷貝機關和賦值操縱都是私人的,這點我們可以對比QObject及其衍生類別的對象哈。
重視:因為拷貝機關和賦值操縱私人的,它也具有auto_ptr同樣的“缺點”——不能用作容器的元素。
QSharedPointer 與 std::shared_ptr
QSharedPointer 與 std::shared_ptr 行動最接近原始指標,是最像指標的"智能指標",應用局限比前面的提到的更廣。
QSharedPointer 與 QScopedPointer 一樣封裝了new操縱符在堆上指派的動態對象,但它實現的是引用計數型的智能指標 ,可以被自由地拷貝和賦值,在隨便率性的處所共用它,當沒有代碼應用(引用計數為0)它時才刪除被封裝的動態指派的對象。shared_ptr也可以安然地放 到標準容器中,並彌補了std::auto_ptr 和 QScopedPointer 因為轉移語義而不能把指標作為容器元素的缺點。
boost::shared_ptr的管理機制其實並不複雜,就是對所管理的對象進行了引用計數,當新增一個boost::shared_ptr就將該對象的引用計數加一;少一個boost::shared_ptr就將該對象的引用計數減一,如果該對象的引用計數為0的時候,說明沒有任何指標對其管理,才調用delete釋放其所佔的記憶體。(參見執行個體二)
和前面介紹的boost::scoped_ptr相比,boost::shared_ptr可以共用對象的所有權,因此其使用範圍基本上沒有什麼限制(還是有一些需要遵循的使用規則,下文中介紹),自然也可以使用在stl的容器中。另外它還是安全執行緒的,這點在多線程程式中也非常重要。
boost::shared_ptr的使用規則:
避免對shared_ptr所管理的對象的直接記憶體管理操作,以免造成該對象的重釋放。
shared_ptr並不能對循環參考的對象記憶體自動管理(這點是其它各種引用計數管理記憶體方式的通病)。
不要構造一個臨時的shared_ptr作為函數的參數。
如下列代碼則可能導致記憶體流失:
void test()
{
foo(boost::shared_ptr<implementation>(new implementation()),g());
}
正確的用法為:
void test()
{
boost::shared_ptr<implementation> sp (new implementation());
foo(sp,g());
}
QWeakPointer 與 std::weak_ptr
強參考型別的QSharedPointer已經很是好用,為什麼還要有弱引用的 QWeakPointer?
QWeakPointer 是為共同 QSharedPointer 而引入的一種智能指標,它更像是 QSharedPointer 的一個助手(因為它不具有通俗指標的行動,沒有重載operator*和->)。它的最鴻文用在於協助 QSharedPointer 工作,像一個觀察遲疑者一樣來觀測資料的應用景象。
weak_ptr 主如果為了避免強引用形成環狀。
在Qt中,對於QObject及其衍生類別對象,QWeakPointer有特別處理懲罰。它可以作為QPointer的調換品
QSharedDataPointer
這是為共同 QSharedData 實現隱式共用(寫時複製 copy-on-write))而供給的便利對象。
Qt中浩繁的類都應用了隱式共用技巧,比如QPixmap、QByteArray、QString、...。而我們為本身的類實現隱式共用也很簡單,比如要實現一個 Employee類:
定義一個只含有一個資料成員(QSharedDataPointer<EmployeeData>) 的 Employee 類
我們須要的所稀有據成員放置於派生自QSharedData的 EmployeeData類中。
QExplicitlySharedDataPointer
這是為共同 QSharedData 實現顯式共用而供給的便利對象。
QExplicitlySharedDataPointer 和 QSharedDataPointer 很是類似,然則它禁用了寫時複製功能。這使得我們建立的對象更像一個指標。
一個例子,接前面的Employee:
#include "employee.h"
int main()
{
Employee e1(1001, "Albrecht Durer");
Employee e2 = e1;
e1.setName("Hans Holbein");
}
寫時複製技巧導致:e1和e2有雷同的工號,但有不合名字。與我們等待的不合,顯式共用可以解決這個題目,這也使得Employee本身更像一個指標。
執行個體解析
執行個體一
1 int main(int argc, char *argv[])
2 {
3 QCoreApplication a(argc, argv);
4 //raw pointer
5 QString *p = new QString("hello");
6 //Implements non-reference-counted strong pointer
7 QScopedPointer<QString> pScopedPointer(new QString("Scoped"));
8 // Build error, can NOT be shared and reference-counted
9 //QScopedPointer<QString> pScopedPointerpScopedPointer2 = pScopedPointer;
10 //Implements reference-counted strong sharing of pointers
11 QSharedPointer<QString> pSmart(new QString("Smart"));
12 QSharedPointer<QString> pSmart2;
13 pSmart2 = QSharedPointer<QString>(new QString("smart 2"));
14 QSharedPointer<QString> pSharedPoninter;
15 // can be shared safely and reference-counted
16 pSharedPoninter = pSmart;
17 qDebug() << *(pSmart.data());
18 qDebug() << *(pSmart2.data());
19 qDebug() << *(pSharedPoninter.data());
20 QTimer *timer = new QTimer();
21 QWeakPointer<QTimer> pWeakPointer = timer;
22 //Weak pointer's resources can be deleted from outside world
23 delete timer;
24 if (pWeakPointer.isNull())
25 {
26 qDebug() << "contained QObject has been deleted";
27 }
28 }
執行個體二
#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
class implementation
{
public:
~implementation() { std::cout <<"destroying implementation\n"; }
void do_something() { std::cout << "did something\n"; }
};
void test()
{
boost::shared_ptr<implementation> sp1(new implementation());
std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n";
boost::shared_ptr<implementation> sp2 = sp1;
std::cout<<"The Sample now has "<<sp2.use_count()<<" references\n";
sp1.reset();
std::cout<<"After Reset sp1. The Sample now has "<<sp2.use_count()<<" references\n";
sp2.reset();
std::cout<<"After Reset sp2.\n";
}
void main()
{
test();
}
該程式的輸出結果如下:
The Sample now has 1 references
The Sample now has 2 references
After Reset sp1. The Sample now has 1 references
destroying implementation
After Reset sp2.
可以看到,boost::shared_ptr指標sp1和sp2同時擁有了implementation對象的存取權限,且當sp1和sp2都釋放對該對象的所有權時,其所管理的的對象的記憶體才被自動釋放。在共用對象的存取權限同時,也實現了其記憶體的自動管理。
參考文獻
http://mobile.51cto.com/symbian-272817.htm
http://www.mysjtu.com/page/M0/S670/670782.html
http://blog.csdn.net/lmh12506/article/details/8897015
http://blog.csdn.net/txb70780533/article/details/5385516
Qt助手