您的位置:首页 > 编程语言 > Qt开发

Qt 隐式共享

2017-03-22 22:00 274 查看
隐式共享又称为回写机制,当两个对象共享同一份数据,如果数据不改变,则不进行数据的复制。而当某个对象需要改变数据时,则执行深拷贝

深拷贝:生成对象的一个完整的复制品。

浅拷贝:是一个引用复制(如 仅复制指向共享数据的指针)

隐式共享可以降低对内存和CPU资源的使用,提高程序的运行效率。它使得在函数中(如参数、返回值)使用值传递更有效率。

例:

QString str1 = "data";
QString str2 = str1;
str2[3] = 'e';
str2[0] = 'f';
str1 = str2;


其中,

(1)QString str2 = str1; 把字符串对象str1赋值给str2(由QString的复制构造函数完成str2的初始化),此时,str2 = “data”。在对str2赋值的时候偶,将发生一次浅拷贝,导致两个QString对象都指向了同一个数据结构。

(2)str2[3] = ‘e’; 对str2的修改,将会导致一次深拷贝,使得str2对象指向一个新的、不同于str1所指的数据结构。此时str1 = “data”, str2 = “date”

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

(4)str1 = str2:; 将str2赋值给str1。此时,str1 之前指向的数据结构将会从内存中释放掉,str1和str2都指向数据结构“fate”。

———-

其实,在使用Qt容器类的时候会可能用到隐式共享机制(implicit sharing),也叫做copy on write。顾名思义,就是说,在内容有变动的情况下才对容器中的数据结构做复制,否则仅做共享。比如:

QList<QString> list1;
list1 << "helianthus";
QList<QString> list2 = list1;

cout << &list1[0] << endl;


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

QList<QString> list1;
list1 << "x";
QList<QString> 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()方法要比使用[]运算子效率高,因为省去了数据结构的复制成本

隐式共享之所以称为copy on write,也就是说只要容器中的数据结构内容发生了变化就不再共享,而要复制。就上一个例子而言,如果对list2做了修改,比如:

list2 << "linux";

那么:

cout << &(list1.at(0)) << endl;

此时list1和list2显示的记忆体位置就是不同的。

再比如:

QList<int> function() {
QList<int> list;
// ...blah..blah
cout << &list << endl;
return list;
}


然后,就可以利用这个函数实现数据共享,又不会数据结构复制:

QList<int> retval= function();
cout << &retval << endl;


在上面这个代码片段中,function()中的list位置和接收function中的list的retval位置是相同的。

总的来说,QT中所有的容器类都支持隐式共享;此外,QByteArray,QBrush,QPen,QPalette,QBitmap,QImage,QPixmap,QCursor,QDir,QFont和QVariant等也都只是隐式共享机制。

而无论是Java风格还是STL风格的迭代器,使用只读迭代器时,背后也都使用到了隐式共享机制,以增加读取的效率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: