一、隐式共享类

在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. 【转载】ID3DXSPRITE接口简单使用

    原文:ID3DXSPRITE接口简单使用 前些日子一直研究DDraw,毕竟是DirectX7的东西了,所以转手用DirectD3D9,用了Surface进行绘图,可是怎么做透明色也都是不行loadfr ...

  2. C#:设置CefSharp的一些参数,比如忽略安全证书

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本次记录如何设置CefSharp忽略安全证书,以及他的一些其他配置 参考网址: https://peter.s ...

  3. DSP5509项目之用FFT识别钢琴音调(2)

    1. 本节主要是学习TLV320AIC32这个音频芯片,Easy5509 开发板上有一个语音编解码芯片 TLV320AIC23.TLV320AIC23 是一个高性能的多媒体数字语音编解码器,它的内部 ...

  4. QQ在线交谈一句代码搞定

    现在有很多网页都有QQ在线咨询,还有什么QQ客服什么的,看着很高大上的一个功能,其实要实现很简单,只需要一句代码就搞定. 还是按以前的套路,先看效果图,再晒源代码 点击图标 再点击 就可以聊天了 再来 ...

  5. 解决WCF传输的数据量过大问题

    今天写了个WCF接口,然后自测通过,和别人联调时报 远程服务器返回错误: (413) Request Entity Too Large        错误!记得以前写的时候也出现过这个错误,大致解决办 ...

  6. Django的简介

    一.MTV模型 Django的MTV模式: Model(模型):和数据库相关的.负责业务对象与数据库的对象(ORM) Template(,模板):放所有的HTML文件 模板语法:目的是将变量(数据库内 ...

  7. java 多路分发

    1.概念 一个函数处理多种类型,其实和多态差不多. 但是要处理两种或者多种类型的数据时,就需要判断每种类型以及每种类型所对应的处理.(PS:我只是在走别人的老路,网上一搜这种概念,博客一大堆,我不知道 ...

  8. 转发——谷歌云官方:一小时掌握深度学习和 TensorFlow

    转发——谷歌云官方:一小时掌握深度学习和 TensorFlow 本文转发自新智元,链接如下: http://mp.weixin.qq.com/s?__biz=MzI3MTA0MTk1MA==& ...

  9. MongoDB 极简实践入门

    原作者StevenSLXie; 原链接(https://github.com/StevenSLXie/Tutorials-for-Web-Developers/blob/master/MongoDB% ...

  10. Java解惑之TreeSet是如何去重的

    引言: 最近在处理一个问题,大致是这个样子,从数据库里面取出一个集合,取出来的数据放到一个JavaBean里面.结果得到的集合长度为1. TreeSetSet的一个实现,默认实现排序:故TreeSet ...