Qt中的隐式共享机制(implicit sharing)

Qt中的隐式共享机制(implicit sharing)

隐式共享

在使用Qt容器类的时候会可能用到隐式共享机制(implicit sharing),隐式共享又叫做回写复制**(copy on write)**。当两个对象共享同一份数据(通过浅拷贝实现数据块的共享)时,如果数据不改变,则不进行数据的复制。而当某个对象需要改变数据时,则进行深拷贝。程序在处理共享对象时,使用深拷贝和浅拷贝这两种方法复制对象, 而深拷贝要占用更多的内存和CPU资源,隐式共享可以降低对内存和CPU资源的使用率,提高程序的运行效率。它使得在函数(如参数、返回值)中使用值传递更有效率。

Qt中支持隐式共享的类包括:QString、QByteArray、QBrush、QPen、QPalette、QBitmap、QImage、QPixmap、QCursor、QDir、QFont和QVariant等。

例如:

QString str1 = "data";  //初始化一个内容为data的字符串
QString str2 = str1; //(a)
str2[3] = 'e';		 //(b)
str2[0] = 'f';		 //(c)
str1 = str2;		 //(d)

其中:

(a) QString str2 = str1; 将该字符串对象str1赋值给另一个字符串str2(由Qtring的复制构造函数完成str2的初始化),此时str2 = “data”。在对str2赋值的时候,将发生一次浅拷贝,导致两个QString都指向同一个数据结构。该数据结构除保存字符串"data"外,还保存了一个引用计时器,以记录字符串数据的引用次数。在这里str1、str2指向同一个数据结构,所以计数器的值为2。

(b) str2[3]=‘e’; 对Qtring对啊str2进行的修改会导致依次深拷贝,使得str2对象指向一个新的、不同于str1所指的数据结构(该数据结构的引用计数为1,因为只有str2指向这个数据结构),同时修改原来的str1指向的数据结构,设置它的引用计数为1(此时只有QString对象str1指向该数据结构)。继而在这个str2指向的、新的数据结构上完成数据的修改。引用计数为1意味着这个数据没有呗共享。此时str2=“date”, str1=“data”。

© str2[0]=‘f’; 进一步对QString对象str2进行修改,但这个操作不会引起任何形式的复制,因为str2指向的数据结构没有被共享。此时str2=“fate”, str1=“data”。

(d) str1=str2; 将str2赋值给str1。此时,str1将它指向的数据结构的引用计时器的值修改为0,也就是说没有QString对象再使用这个数据结构了。因此str1指向的数据结构将会从内存中释放掉。该操作的结果是QString对象str1和str2都指向字符串为"fate"的数据结构,该数据结构的引用计数为2。

Qt中的隐式共享机制(implicit sharing)_第1张图片

再例如:

QPixmap pix1, pix2;
pix1.load("image.jpg");
pix2 = pix1;            // pix1和pix2共享数据

QPainter paint;
paint.begin(&pix2);      //pix2 自动脱离共享数据,因为调用函数QPainter::begin()时,系统认为画一副图将会改变这幅图。
paint.drawText(0,50, "Hi");
paint.end();

另外需要注意区分[]和at,例如对以下程序:(参考https://blog.csdn.net/u011450537/article/details/41674245)

QList list1; 
list1 << "helianthus"; 
QList list2 = list1;   
cout << &list1[0] << endl; 
cout << &list2[0] << endl;

在这个例子中使用了[]运算子,list1和list2中的数据结构经过了复制,所以并不是共享的。因此最后显示的两个记忆体位置并不相同,但是使用了at()时的情况是一样的:

QList list1; 
list1 << "x"; 
QList list2 = list1; 
//QList::at(int i) const:Returns the item at index position i in the list. i must be a 
//valid index position in the list (i.e., 0 <= i < size())  
cout << &(list1.at(0)) << endl; 
cout << &(list2.at(0)) < < endl;

所以,在只读的情况下,使用at()方法要比使用[]运算子效率高,因为省去了数据结构的复制成本。

你可能感兴趣的:(Qt开发,qt,开发语言,c++)