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,这样成员数据不再共享。
以上自己写的尚有不足之处,希望大家发现错误能指正。