最近學習Qt,在深入了解容器類的時候,特意關注了下隱含共享機制,以下為書中原文,最後部分是自己的一些總結。
《C++ GUI Qt4編程》摘選:
隱含共享在後台自動運行,所以我們不必再編寫任何代碼來促進這個優化過程發生。但弄明白它到底如何工作,的確是一件有益的事情。為此,我們將研究一個例子,看看在它的神秘面紗下面到底發生了什麼。這個例子使用了QString,它是眾多的隱含共享類之一。
QString str1 = "Humpty"; QString str2 = str1;
我們設置str1為"Humpty"並令str2等於str1。在這一點上,QString的兩個對象都指向內存中相同的內部數據結構。與字符數據一起,數據結構保存一個引用技術,以指出有多少QString指向相同的數據結構。因為str1和str2都指向相同的數據,所以引用計數的值為2。
str2[0] = 'D';
當修改str2時,它首先將對數據進行深層賦值,以確保str1和str2指向不同的數據結構,然後才將新數值應用於它所復制的數據。str1的數據("Humpty")的引用計數變為1,且把str2的數據("Dumpty")的引用計數也設為1.引用計數為1表示數據並未被共享。
1 str2.truncate(4);
如果再次修改str2,則由於str2數據的引用計數為1,將不會發生數據復制。truncate()函數直接對str2的數據進行操作,導致字符串變為"Dump"。引用計數保持為1.
1 str1 = str2;
當將str2賦給str1時,str1的數據的引用計數降為0,這意味著沒有一個QString仍在使用"Humpty"數據。這樣,這些數據就從內存中釋放。兩個QString都指向"Dump",現在它的引用計數就是2了。
由於引用計數中的競爭情況,數據共享在多線程程序中通常只是作為一個選項而沒有給與關注。使用Qt,這並不是一個問題。在內部,容器類使用匯編語言指令執行基本的引用計數。通過QSharedData和QSharedDataPointer類,Qt的用戶也可以使用這項技術。
以下為自己總結的部分:
這就像我們使用智能指針一樣,例如shared_ptr<T> 對內存中同一個指向內存單元的對象進行托管。我們在做Qt程序時可以用子類繼承父類的方式構造一個共享數據類,並繼承了父類QSharedData的引用計數規則,並再構造一個類對繼承自共享數據類的子類進行成員方法操作例如:
1 #include <QSharedData> 2 #include <QString> 3 4 class EmployeeData : public QSharedData 5 { 6 public: 7 EmployeeData() : id(-1) { } 8 EmployeeData(const EmployeeData &other) 9 : QSharedData(other), id(other.id), name(other.name) { } 10 ~EmployeeData() { } 11 12 int id; 13 QString name; 14 }; 15 16 class Employee 17 { 18 public: 19 Employee() { d = new EmployeeData; } 20 Employee(int id, const QString &name) { 21 d = new EmployeeData; 22 setId(id); 23 setName(name); 24 } 25 Employee(const Employee &other) 26 : d (other.d) 27 { 28 } 29 void setId(int id) { d->id = id; } 30 void setName(const QString &name) { d->name = name; } 31 32 int id() const { return d->id; } 33 QString name() const { return d->name; } 34 35 private: 36 QSharedDataPointer<EmployeeData> d; 37 };
為此,我們通過構造Employee ep1(1001, "XIAOMING");來創建一個對象,並將Employee ep2 = ep1;進行復制構造,因為Employee內部私有成員是一個包含了EmployeeData的共享數據指針,所以我們的兩個對象共用一個,引用計數為2。如果我們對ep2進行了setName的操作,這樣ep2就會自我復制一份,並修改內部成員,ep1的引用計數變為1,ep2的引用計數也變為1,這樣成員數據不再共享。
以上自己寫的尚有不足之處,希望大家發現錯誤能指正。