| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> Qt 之 智能指针汇总 -> 正文阅读 |
|
[C++知识库]Qt 之 智能指针汇总 |
来源 文章目录: 代码中出现一个bug,最终发现是由于在某个特殊情况下出现了使用垂悬指针,造成了程序崩溃,进而学习了解了Qt的智能指针机制。 一、悬垂指针的问题如图,有两个指针a和b指向同一片内存,如果删除其中一个指针a,再去使用指针b的话,程序会崩溃。因为指针b此时已经是一个垂悬指针(Dangling pointer)了,它指向的内存已经被释放不再有效。 垂悬指针使用指针b之前先判断b是否为空,这个做法在这里是不起作用的。问题的本质是通过指针a去释放内存时,指针b没有同步地置为空。 二、Qt中的智能指针Qt提供了若干种智能指针:QPointer、QSharedPointer、QWeakPointer、QScopedPointer、QScopedArrayPointer、QSharedDataPointer、QExplicitlySharedDataPointer。 1、QPointerQPointer只用于QObject的实例。如果它指向的对象被销毁,它将自动置空。 QPointer这是Qt体系下的专门用于QObject的智能指针。常见使用方法:
2、QSharedPointer & QWeakPointerQSharedPointer是引用计数(强)指针,当所有强指针销毁时,实际对象才会销毁。QWeakPointer是弱指针,可以持有对QSharedPointer的弱引用。它作为一个观察者,不会引起实际对象销毁,当对象销毁时会自动置空。
//使用
3、QScopedPointerQScopedPointer保证当当前范围消失时指向的对象将被删除。它拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让,因为它的拷贝构造和赋值操作都是私有的。相当于C++中的std::unique_ptr,实例代码:
4、其他智能指针QScopedArrayPointer:一个QcopedPointer,默认删除它指向Delete []运算符的对象。为方便起见,还提供了操作符[]。QSharedDataPointer/QExplicitySharedDataPointer搭配QSharedData类一起使用,以实现自定义隐式共享或显式共享类。 三、实践记录1、通常,要使用弱指针,必须将其转换为强指针,因为这样的操作确保了只要您使用它就会生存。这相当于“锁定”访问的对象,并且是使用弱指针指向的对象的唯一正确方法。并且转换后使用前需要判空。
2、最好在new的时候就用QSharedPointer封装,并管理起来。
3、使用智能指针包装后,不要直接去删除指针对象。
4、不要多次使用同一裸指针构造QSharedPointer。Plot *plot = new Plot();
5、不要使用new直接构造QWeakPointer对象,它只能通过QSharedPointer的赋值来创建。
9、关于Qt元对象系统自动析构和Qt智能指针自动析构相冲突的问题,经初步实验Qt4.8中应该已经解决了?不过实际中,可以让数据用智能指针管理,不用父子层级;窗体控件用父子层级,不用智能指针。 四、 用法举例1、QWeakPointer举例QWeakPointer不能用于直接取消引用指针,但它可用于验证指针是否已在另一个上下文中被删除。并且QWeakPointer对象只能通过QSharedPointer的赋值来创建。 需要注意的是,QWeakPointer不提供自动转换操作符来防止错误发生。即使QWeakPointer跟踪指针,也不应将其视为指针本身,因为它不能保证指向的对象保持有效。 说了那么多,QWeakPointer到底有什么用呢? 在概述中我们说到,QWeakPointer 是为配合 QSharedPointer 而引入的一种智能指针。而什么叫循环引用,就是说:两个对象互相使用一个 QSharedPointer成员变量指向对方(你中有我,我中有你)。由于QSharedPointer是一个强引用的计数型指针,只有当引用数为0时,就会自动删除指针释放内存,但是如果循环引用,就会导致QSharedPointer指针的引用永远都不能为0,这时候就会导致内存无法释放。 示例
在构造函数中调用test()函数,执行完过后应该会自动释放parent和children对象,但是由于相互引用,在退出之前,引用计数为2,退出之后引用计数还是1,所以导致不能自动释放,并且此时这两个对象再也无法访问到。运行过后发现并没有进入到Parent和Children的析构函数中。这就导致了内存泄漏。 那么该如何解决这个问题呢?
改成
这时候再次运行,就会看到输出:
这是因为在test()退出之前引用计数是1,函数退出之后就自动析构,这就解除了上面的循环引用。 2、QScopedPointer 与 std::unique_ptr它们概念上应该是是一样的。下面不再区分: 这是一个很类似auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。但它的所有权更加严格,不能转让,一旦获取了对象的管理权,你就无法再从它那里取回来。 无论是QScopedPointer 还是 std::unique_ptr 都拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让。因为它的拷贝构造和赋值操作都是私有的,这点我们可以对比QObject及其派生类的对象哈。 用法 (来自Qt的manual):
我们在异常处理语句中多次书写delete语句,稍有不慎就会导致资源泄露。采用智能指针后,我们就可以将这些异常处理语句简化了:
另,我们一开始的例子,也是使用这两个指针的最佳场合了(出main函数作用域就将其指向的对象销毁)。 注意:因为拷贝构造和赋值操作私有的,它也具有auto_ptr同样的“缺陷”——不能用作容器的元素。 3、测试样例
|
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 4:42:10- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |