程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Qt隱含共享是如何工作的,Qt隱含共享工作

Qt隱含共享是如何工作的,Qt隱含共享工作

編輯:C++入門知識

Qt隱含共享是如何工作的,Qt隱含共享工作


  最近學習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,這樣成員數據不再共享。

  以上自己寫的尚有不足之處,希望大家發現錯誤能指正。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved