Q_DISABLE_COPY、Q_DISABLE_MOVE、Q_DISABLE_COPY_MOVE用法详解及总结
1.前言
在编程中,会用到某些资源,这些资源有的在整个应用程序期间是唯一的;是不能通过拷贝、赋值的方法存在多份的,如STL的std::unique_ptr指针指向的资源。现实中这样的资源有:文件指针、串口句柄等。试想如果存在多个同一个文件的句柄或同一个串口的句柄,就可能在同一时刻对同一文件或串口进行写操作,这样会导致文件内容杂乱、损坏;现实中,当一个串口被一个程序占用时,另外一个程序尝试打开这个串口会报错。为了防止资源通过拷贝、赋值方式存在多份,Qt引入了Q_DISABLE_COPY、Q_DISABLE_MOVE、Q_DISABLE_COPY_MOVE宏。
2.删除函数、拷贝/移动构造函数、拷贝/移动赋值函数
说明:本节都是C++11中的知识,如果读者对本节很熟悉,可以跳过本节的学习。本节只是粗略提到这几个函数的说明,更深入的用法,可以自行学习C++11来进一步深入。
如下代码:
class MyClass{private:MyClass(const MyClass &) = delete; // 拷贝构造函数被删除MyClass(const MyClass &&) = delete;// 移动构造函数被删除MyClass &operator=(const MyClass &) = delete; // 拷贝赋值函数被删除MyClass& operator=(MyClass&&);// 移动赋值函数被删除,注意没有const};
在上面代码中,声明一个名为 MyClass的类。其中第4、5、6、7行分别为:复制构造函数、移动构造函数、拷贝赋值函数、移动赋值函数。因为这几个函数被标注为delete,即这几个函数被标注为删除的,所以调用这几个函数会报错。报错类似如下:
尝试引用已删除的函数
C++11正是通过这种方式保证资源无法通过拷贝、赋值方式存在多份。
说明:C++基础不扎实的读者就会发出疑问:既然外层不能调用这些函数,不在cpp文件中实现构造、赋值函数不就行了吗?为何还要费心费力的写那么多标记为delete的函数呢?按照C++的规则:这几个函数如果不手动写,则编译器会为我们默认生成,默认生成的函数按位进行拷贝,反映到拷贝构造函数上,就是浅拷贝,所以不写和手动写但标记为delete是完全不同的。
3.Qt这几个宏的说明
Q_DISABLE_COPY宏等同于2节第4、6行代码功能,即拷贝构造和拷贝赋值函数都被删除。
Q_DISABLE_MOVE宏等同于2节第5、7行代码功能,即移动构造和移动赋值函数都被删除。
Q_DISABLE_COPY_MOVE宏等同于2节第4、5、6、7行代码功能,即拷贝构造、拷贝赋值函数、移动构造、移动赋值函数都被删除。
使用这几个宏时需要注意如下几点:
本类表示的对象不能通过拷贝、赋值的方法存在多份,只能唯一存在。
当使用这几个宏时,将其放到类的private标识区。
这几个宏的参数为类名。
4.单例模式
对于在整个应用程序中,只能存在一份的对象,在设计中,一般通常采用单例设计模式。如下为Qt
下的单例模式的.h文件
class MyClass:public QObject{private:MyClass(QObject *parent = Q_NULLPTR);~MyClass();MyClass(const MyClass &) = delete; // 拷贝构造函数被删除MyClass(const MyClass &&) = delete;// 移动构造函数被删除MyClass &operator=(const MyClass &) = delete; // 拷贝赋值函数被删除MyClass& operator=(MyClass&&);// 移动赋值函数被删除,注意没有const
private:static MyClass* createAndGetInstance(); // 创建并返回MyClass类对象的唯一实例,也即m_pInstance
private:// 唯一实例static MyClass* m_pInstance;};
上面写了一大堆删除函数,对程序员来说是个负担,有了上面的宏后,则代码可以简写为:
class MyClass:public QObject{private:MyClass(QObject *parent = Q_NULLPTR);~MyClass();
private:Q_DISABLE_COPY_MOVE(MyClass)
private:static MyClass* createAndGetInstance(); // 创建并返回MyClass类对象的唯一实例,也即m_pInstance
private:// 唯一实例static MyClass* m_pInstance;};
关于单例模式的实现,可参考如下链接:
《单例》。
《单例模式(Qt实现)》。
《Q_GLOBAL_STATIC用法及如何保证多线程下的单例模式安全性》。
5.附加说明
QObject 中没有提供一个拷贝构造函数和赋值操作符给外界使用,其实拷贝构造和赋值的操作都是已经声明了的,但是它们被使用了Q_DISABLE_COPY() 宏放在了private区域。因此所有继承自QObject的类都使用这个宏声明了他们的拷贝构造函数和赋值操作符为私有。
为什么要这样做?我们都知道Qt对标准C++增加了一些功能:signals, slots, object properties, events, event filters, string translation, timers,object trees, guarded pointers, dynamic cast.
新加入的这些功能就要求我们把每一个QObject的对象看做是唯一(identities)的。唯一的意思就是不能通过拷贝或者赋值操作制作出一个一模一样的复制体。试想如果我们有一个QPushButton对象btnSubmit,如果我们可以复制出一个和btnSubmint完全一样的button对象,那么新的button对象的名字应该是什么?如果也叫btnSubmit,当我们给其中的btnSubmit接收事件或发出信号时,系统如何区分把事件由哪个button对象接收,或者哪个对象发送了信号?
我们知道在各种容器中能以value方式存放的类型,必须有默认的构造函数,拷贝构造函数和赋值操作。由于QObject及所有继承自它的子类都没有提供拷贝构造和赋值操作,当我们使用QList时,编译器就会报错。如果我们要在容器中存储这中类型的对象,我们就要使用它们的指针。如QList<QObject *>。如下代码:
QWidget w1 = QWidget();
上面的=号操作符会调用拷贝赋值函数,根据上述的规则,会报错,报错如下:
转到QWidget类的声明处,可以看到如下:
即QWidget的拷贝赋值函数被删除了。
Q_DISABLE_COPY、Q_DISABLE_MOVE、Q_DISABLE_COPY_MOVE用法详解及总结相关推荐
- python argv 详解_Python3 sys.argv[ ]用法详解
sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个"外部"很关键,因为我们从外部取得的参数可以是多个,所以获得的是一个列表(list),也就是说sys.argv其实可 ...
- oracle中的exists 和 not exists 用法详解
from:http://blog.sina.com.cn/s/blog_601d1ce30100cyrb.html oracle中的exists 和 not exists 用法详解 (2009-05- ...
- ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)
ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多) https://blog.csdn.net/qq_25221835/article/details/82762416 post ...
- python的继承用法_【后端开发】python中继承有什么用法?python继承的用法详解
本篇文章给大家带来的内容是关于python中继承有什么用法?python继承的用法详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 面向对象三大特征 1.封装:根据职责将属性和方法 ...
- C++中substr()函数用法详解
C++中substr()函数用法详解 原型: string substr (size_t pos = 0, size_t len = npos) const; 返回一个新构造的string对象,其值初 ...
- php theme_path,PHP_Yii2主题(Theme)用法详解,本文实例讲述了Yii2主题(Theme) - phpStudy
Yii2主题(Theme)用法详解 本文实例讲述了Yii2主题(Theme)用法.分享给大家供大家参考,具体如下: 首先看看主要的配置方式: 'components' => [ 'view' = ...
- LayoutInflater的inflate函数用法详解
LayoutInflater的inflate函数用法详解 LayoutInflater作用是将layout的xml布局文件实例化为View类对象. 获取LayoutInflater的方法有如下三种: ...
- Ext.Net学习笔记22:Ext.Net Tree 用法详解
上面的图片是一个简单的树,使用Ext.Net来创建这样的树结构非常简单,代码如下: <ext:TreePanel runat="server"><Root> ...
- WinDbg用法详解
WinDbg用法详解 对WinDbg的方方面面作了详细的讲解. 转载于:https://blog.51cto.com/laokaddk/125111
最新文章
- 查看核心交换机CPU时的几个参数~~
- Linux 构建一些 开机就可以使用的命令
- 【洛谷P2743】【poj 1743】[USACO5.1]乐曲主题Musical Themes
- Gray Code(格雷码) C++多方法实现
- TensorFlow COCO
- JS+PHP实现登录后自动执行之前的操作
- 豆瓣评分8.0以上数据分析R、MySQL、Python等书籍,45本包邮送到家
- 【转载】Matlab画图命令介绍
- kotlin数组和集合
- 微信小程序:图片秒加水印制作生成
- Airflow实战--获取REST参数并通过Xcom传递给Bash算子
- 三相维也纳pfc,开关电源,三相AC输入无桥pfc±400vDC输出
- 09-Httprunner-生成测试报告
- 东方梦符祭服务器维护能玩吗,东方梦符祭新手经营攻略 东方梦符祭怎样玩
- 【小知识】linux下ls与ll的区别
- 2022年全国职业院校技能大赛网络安全赛卷(中职组)卷8
- 7-4 病毒感染检测 (15 分)
- SYN480R模块解码EV1527教程
- 阿里妈妈CMO沈威:用品牌建设视角看待电商营销
- 【API】聊天机器人接口
热门文章
- 转:这些年我们爱犯的弱智错误(菜鸟必看)
- 单片机c语言三角波采样点,E题_江苏赛区_南京信息工程大学——放大器非线性失真分析装置 一等奖...
- 练习(二)——威斯康辛乳腺癌数据集
- 聚焦人生最后阶段:“互联网+殡葬”行业分析
- tenacity retry重试和defaultdict包、sorted字典排序
- com.fasterxml.jackson.databind.exc.MismatchedInputException
- Windows 11适合玩游戏吗?
- 会计要素及其确认条件、资产、负债、所有者权益、收入、费用、利润(本章重在理解)
- Unity —— 针对DynamicBone插件的迭代来实现布料模拟
- 牛客 数三角(求多少个钝角三角形 极角排序)