Qt——数据的隐式共享
一、隐式共享类
在Qt中有很多隐式共享类( Implicitly Shared Classes ),什么是隐式共享呢,请参考官方文档的说明。
好吧,翻译一下——
许多C++类隐式地共享数据,使得资源使用最大化,以及对象拷贝最小化。隐式共享类在传参时既安全又高效,因为只传了一个指向数据的指针,并且只有给它写入时数据才会被拷贝。
看了概念之后是不是有点眉目了呢?至少明白隐式共享与C++中参数传值/传引用有关。
二、山重水复
首先定义一个如下的类
class TestClass
{
public:
TestClass(int i)
{
data = i;
}
private:
int data;
};
它有一个整型的数据成员,通过构造函数可以给它传一个整数数据。
然后按照下面的方式定义它的2个对象
TestClass a(5);
TestClass b = a;
此时虽然对象a和b中的数据一样,都是5,但它们各自都有一份整型值的拷贝,这就造成了内存浪费。
三、柳暗花明
于是我们想到一个节约内存的方法:
当几个不同对象的数据一样时,保留一份数据就够了;只有当某个对象发生了改变,才用得着一份新的数据。
这涉及到一个新的名词,叫做“引用计数”( reference count )。用一个数来记录有多少对象正在使用同一份数据,当一个新对象被创建,计数加一,当一个对象被销毁,计数减一。如果计数为0,意味着没有对象使用它了,从而将数据释放。
改变上面的程序来简单解释一下——
class DataArea{
public:
DataArea(int data)
{
this->data = data;
count = 1;
}
void increaseRef()
{
count++;
}
void decreaseRef()
{
if (--count == 0)
delete this;
}
private:
int count;
int data;
};
class TestClass{
public:
TestClass(int i)
{
dataArea = new DataArea(i);
}
TestClass(const TestClass &data)
{
dataArea = data.dataArea;
dataArea->increaseRef();
}
TestClass &operator=(const TestClass &testObj)
{
if (dataArea != testObj.dataArea){
dataArea->decreaseRef();
dataArea = testObj.dataArea;
dataArea->increaseRef();
}
return *this;
}
~TestClass()
{
dataArea->decreaseRef();
}
private:
DataArea *dataArea;
};
类TestClass是我们直接使用的类,这个类有一个私有成员指向数据区,如果不同对象有相同的数据,那么它们指向同一个数据区。
且看下面的用法:
TestClass a(5);
TestClass b = a;
b = TestClass(2);
跟踪一下a和b的数据区域指针有什么变化——
TestClass a(5);
1.进入类TestClass的构造函数
2.进入类DataArea的构造函数
3.count = 1、data = 5 (引用计数为1,数据是5)
TestClass b = a;
1.进入类TestClass的拷贝构造函数
b和a中的数据指针指向同一个对象
2.调用计数增加函数
count = 2、data = 3
b = TestClass(2);
1.TestClass(2) —— TestClass的构造函数
2.类DataArea的构造函数
count = 1、data = 4
3.赋值运算符——
b(同时也是a)的数据区指针调用计数减一函数,a计数变为1
4.改变b的数据区指针,指向TestClass(2)对象的数据区
b(同时也是对象TestClass(2))的数据区指针调用计数加一函数
b的计数变为2
5.析构TestClass(2)这个对象,进入计数减一函数
b的计数变为1
当然,程序结束时,会调用a和b的析构函数,计数减为0,释放数据区。
上面这些其实就是我们平时说的“写时复制”(copy on write)。
为了方便理解,上面的例子可能不太好。当一个对象很大很复杂的时候,直接拷贝可能对效率有很大影响,这时就能体现出写时复制的优势了。
四、Qt中的隐式共享
以QString为例,QString中有一个 constData() 函数,该函数返回一个指向QString中存储的数据的指针。
QString a("Diao");
QString b = a;
qDebug() << a;
qDebug() << b;
qDebug() << &a;
qDebug() << &b;
qDebug() << a.constData();
qDebug() << b.constData();
a[0] = 'M';
qDebug() << a;
qDebug() << b;
qDebug() << &a;
qDebug() << &b;
qDebug() << a.constData();
qDebug() << b.constData();
结果如下:

懂了?
Qt——数据的隐式共享的更多相关文章
- 关于QT中的隐式共享
网上关于隐式共享的解释很多,在此不再陈述.本文主要是记录一下自己学习隐式共享的坑点: 即:隐式共享只发生在非指针的情况下!!!! 如下代码: QImage image1; QImage image2; ...
- C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享
下面是C++中定义的深,浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用.以下情况都会 ...
- Qt隐式共享与显式共享
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Amnes1a/article/details/69945878Qt中的很多C++类都使用了隐式数据共 ...
- Qt隐式共享机制
1.浅拷贝 浅拷贝-引用类型.浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同),对其中任何一个对象的改动都会影响另外一个对象. 2.深拷贝 而深拷贝-值类型.深拷贝是指源对象与 ...
- 可恶的QT隐式共享
这个问题隐藏的很深,一般不容易察觉它造成的问题,而只是享受它提供的好处(节省内存,而且速度更快). 但我发现它现在至少造成两个问题: 1. 把大量的QString放到QMap里,使用完毕后清空QMap ...
- 01Qt中的隐式共享
隐式共享 隐式共享又称为回写复制(copy on write).当两个对象共享同一分数据时(通过浅拷贝实现数据共享),如果数据不改变,则不进行数据的复制.而当某个对象需要需要改变数据时,则进行深拷 ...
- QVector 和vector的比较(QVector默认使用隐式共享,而且有更多的函数提供)
QVector和vector的比较: Qvector默认使用隐式共享,可以用setSharable改变其隐式共享.使用non-const操作和函数将引起深拷贝.at()比operator[](),快, ...
- 《前端之路》之二:数据类型转换 && 隐式转换 || 显式转换
目录 02:数据类型转换 && 隐式转换 || 显式转换 02:数据类型转换 && 隐式转换 || 显式转换 在上一个章节中,我们介绍了 JavaScript 的基本的 ...
- 基于GPS数据建立隐式马尔可夫模型预测目的地
<Trip destination prediction based on multi-day GPS data>是一篇在2019年,由吉林交通大学团队发表在elsevier期刊上的一篇论 ...
随机推荐
- QTC++监控USB插拔
#if defined(Q_OS_WIN) #include <qt_windows.h> #include <QtCore/qglobal.h> #include <d ...
- ADO.NET操作MySQL数据库
前言 ADO.NET包括5大对象,分别是Connection.Command.DataReader.DataSet.DataAdapter,使用ADO.NET访问数据库有两个步骤:建立数据库连接.读取 ...
- sqlserver(2012)清理tempdb
当数据库运行时间长了之后,tempdb变得特别大,几十G,受不了啊:当然我们知道重启 SQL Server服务的话,tempdb数据库会自动重新创建的,从而使 tempdb 回归到初始大小.但是这是生 ...
- div不设置高度背景颜色或外边框不能显示的解决方法
在使用div+css进行网页布局时,如果外部div有背景颜色或者边框,而不设置其高度,在浏览时出现最外层Div的背景颜色和边框不起作用的问题. 大体结构<div class="oute ...
- Linux系统服务(daemon)(鸟哥Linux私房菜笔记)
Linux系统服务(daemon) 一.SystemV的init管理机制(脚本式启动)1.服务启动分类stand alone 独立启动模式super daemon 总管程序 2.服务的启动.关闭与观察 ...
- 高可用Kubernetes集群-7. 部署kube-controller-manager
九.部署kube-controller-manager kube-controller-manager是Kube-Master相关的3个服务之一,是有状态的服务,会修改集群的状态信息. 如果多个mas ...
- Pvmove中断后恢复LV状态
Pvmove中断后恢复LV状态 pvmove执行时关闭中断窗口后,pvmove进程会被强制杀掉,从而导致lv的状态异常,无法重新进行pvmove和其他lvm镜像增加相关操作,可以通过如下方式修复: ...
- vim—多行注释、取消多行注释
多行注释 命令模式: (1)将光标放在要注释的行首,按下组合键ctrl + v ,然后按上下键选取要注释的行. (2)按下大i键,然后插入要注释的符号 # (3)按ESC键,退出后,就会全部注释. 取 ...
- Fast R-CNN学习总结
Fast R-CNN是R-CNN的改良版,同时也吸取了SPP-net中的方法.在此做一下总结. 论文中讲到在训练阶段,训练一个深度目标检测网络(VGG16),训练速度要比R-CNN快9倍左右,比SPP ...
- KETTLE元数据表
表名 说明 R_CLUSTER R_CLUSTER_SLAVE R_CONDITION R_DATABASE 数据库连接信息 R_DATABASE_ATTRIBUTE 数据库属性 R_DATABASE ...