一、隐式共享类

在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. 用sudo 运行命令的时候,环境变量用的是super用户的环境变量

    比如今天在~/.bashrc设置了JAVA_HOME, 而sudo运行命令的时候却显示没有设置可用的JAVA_HOME

  2. 记一次SpringBoot使用WebUploader的坑

    问题: B/S通常都会涉及到文件的上传,普通文件上传使用文件框,后台接收文件即可 我遇到的问题是要开发一个大文件上传的功能,那就肯定要支持文件的分片 分析: 1.参考网上的资料后,通常的多文件和大文件 ...

  3. PostgreSQL参数学习:max_wal_senders

    磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面:PostgreSQL基础知识与基本操作索引页    回到顶级页面:PostgreSQL索引页[作者 高健@博客园  luckyjackgao@g ...

  4. [arc063F]Snuke's Coloring 2-[线段树+观察]

    Description 传送门 Solution 我们先不考虑周长,只考虑长和宽. 依题意得答案下限为max(w+1,h+1),并且最后所得一定是个矩形(矩形内部无点). 好的,所以!!!答案一定会经 ...

  5. [BZOJ1492][NOI2007]cash-[cdq分治]

    Description 传送门 Solution 首先,最优情况一定是某一天把所有金券卖出或买入是最优的. 在金券一定的情况下,分散卖一定没有统一在最优的那天卖更优. 然后,我们假定在某一天卖,则在该 ...

  6. 【CF813D】Two Melodies

    [CF813D]Two Melodies 题面 洛谷 题解 $dp$: 设$f[i][j]$表示第一个集合以$i$结尾.第二个集合以$j$结尾的合法长度之和最大是多少 明显有$f[i][j]=f[j] ...

  7. iOS 影音新格式 HEIF HEVC

    苹果在 iOS 11 的发布会上,推出了两种新的媒体格式 HEIF HEVC,都是为了保证画质的情况下,大大减少视频.照片的大小. 一.简介 HEVC全称 High Efficiency Video ...

  8. ES6 localStorage 类库

    无意中看到的,记录下. 用到了es6语法.支持在js中写构造函数 class CovLocalDB { constructor (name) { this.LS = null this.name = ...

  9. Windows下python环境的安装

    1.下载安装包 https://www.python.org/downloads/ 2.安装 默认安装路径:C:\python27 3.配置环境变量 [右键计算机]-->[属性]-->[高 ...

  10. linux下,将一个目录中的图片文件合成为gif图片

    # {} 为文件所在目录位置 # {} 为gif图片位置 convert -delay -depth -layers optimize -quality -loop {} {}