一、隐式共享类

在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——数据的隐式共享的更多相关文章

  1. 关于QT中的隐式共享

    网上关于隐式共享的解释很多,在此不再陈述.本文主要是记录一下自己学习隐式共享的坑点: 即:隐式共享只发生在非指针的情况下!!!! 如下代码: QImage image1; QImage image2; ...

  2. C++中的深拷贝和浅拷贝 QT中的深拷贝,浅拷贝和隐式共享

    下面是C++中定义的深,浅拷贝 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用.也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用.以下情况都会 ...

  3. Qt隐式共享与显式共享

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Amnes1a/article/details/69945878Qt中的很多C++类都使用了隐式数据共 ...

  4. Qt隐式共享机制

    1.浅拷贝 浅拷贝-引用类型.浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同),对其中任何一个对象的改动都会影响另外一个对象. 2.深拷贝 而深拷贝-值类型.深拷贝是指源对象与 ...

  5. 可恶的QT隐式共享

    这个问题隐藏的很深,一般不容易察觉它造成的问题,而只是享受它提供的好处(节省内存,而且速度更快). 但我发现它现在至少造成两个问题: 1. 把大量的QString放到QMap里,使用完毕后清空QMap ...

  6. 01Qt中的隐式共享

    隐式共享 ​ 隐式共享又称为回写复制(copy on write).当两个对象共享同一分数据时(通过浅拷贝实现数据共享),如果数据不改变,则不进行数据的复制.而当某个对象需要需要改变数据时,则进行深拷 ...

  7. QVector 和vector的比较(QVector默认使用隐式共享,而且有更多的函数提供)

    QVector和vector的比较: Qvector默认使用隐式共享,可以用setSharable改变其隐式共享.使用non-const操作和函数将引起深拷贝.at()比operator[](),快, ...

  8. 《前端之路》之二:数据类型转换 && 隐式转换 || 显式转换

    目录 02:数据类型转换 && 隐式转换 || 显式转换 02:数据类型转换 && 隐式转换 || 显式转换 在上一个章节中,我们介绍了 JavaScript 的基本的 ...

  9. 基于GPS数据建立隐式马尔可夫模型预测目的地

    <Trip destination prediction based on multi-day GPS data>是一篇在2019年,由吉林交通大学团队发表在elsevier期刊上的一篇论 ...

随机推荐

  1. ubuntu装openVPN会遇到的问题

    与Windows系统相比,Linux下安装OpenVPN的过程就显得有点曲折. 如果你使用的是Ubuntu系统,你可以直接使用命令sudo apt-get install -y openvpn来安装O ...

  2. [BZOJ2127]happiness-[网络流-最小割]

    Description 传送门 Solution 按照最小割的思路考虑. 根据题意,当两个人都选文(理),需要砍掉两个人都选理(文)的加成:如果两个人选的不一样,就要都砍掉. 这是一个网络流建模的套路 ...

  3. OpenCV中Mat操作clone() 与copyto()的区别

    OpenCV中Mat操作clone() 与copyto()的区别 // Mat is basically a class with two data parts: the matrix header ...

  4. 图论-最短路径--3、SPFA算法O(kE)

    SPFA算法O(kE) 主要思想是:     初始时将起点加入队列.每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队.直到队列为空时算法结束.     这个算 ...

  5. 无旋treap的区间操作实现

    最近真的不爽...一道维修数列就做了我1上午+下午1h+1晚上+晚上1h+上午2h... 一道不错的自虐题... 由于这一片主要讲思想,代码我放这里了 不会无旋treap的童鞋可以进这里 呵呵... ...

  6. 【MySQL高级特性】高性能MySQL第七章

    2017-07-25 14:15:43 前言:MYSQL从5.0和5.1版本开始引入了很多高级特性,例如分区.触发器等,这对有其他关系型数据库使用 背景的用户来说可能并不陌生.这些新特性吸引了很多用户 ...

  7. Zigbee系列(概览)

    Zigbee技术特点 低速率: 数据传输速率只有20~250kb/s, 2.4GHZ提供250kb/s, 915MHz对应40kb/s, 868Mhz对应20kb/s 低功耗:睡眠模式设备使用电池供电 ...

  8. 车架号识别,VIN码识别 助力汽车后市场

    又有一家汽配圈新贵引入了小译家的 车架号识别(VIN码识别)技术 那就是明觉科技 是一个服务于汽车后市场 集数据服务.行业数据挖掘 及“互联网+”为一体的汽配信息协作平台 旗下拥有一款全车零配件信息智 ...

  9. JMeter:全面的乱码解决方案【转】

    本文是转自https://www.cnblogs.com/mawenqiangios/p/7918583.html 感谢分享者   中文乱码一直都是比较让人棘手的问题,我们在使用Jmeter的过程中, ...

  10. sql 命令使用简单记录

    半个月前就想记下用过的SQL命令的!!!     主题: 按时间查询: https://blog.csdn.net/hejpyes/article/details/41863349   左关联: se ...