Qt 智能指针学习

原地址:http://blog.csdn.net/dbzhang800/article/details/6403285

从内存泄露开始?

很简单的入门程序,应该比较熟悉吧 ^_^

#include <QApplication>
#include <QLabel>int main(int argc, char *argv[])
{QApplication app(argc, argv);QLabel *label = new QLabel("Hello Dbzhang800!");label->show();return app.exec();
}

在  从 Qt 的 delete 说开来 一文中,我们提到这个程序存在内存泄露(表现就是析构函数不被调用),而且当时给出了三种解决方法:

  • 将label对象分配到stack而不是heap中
  • 给label设置标记位Qt::WA_DeleteOnClose

  • 自己调用delete来删除通过new分配到heap中的 label 对象

注:

  • 为了能清楚观察构造和析构函数的调用,我们可以简单子类化了一下QLabel,然后用Label取代前面的QLabel
    class Label :public QLabel
    {
    public:Label(const QString& text, QWidget *parent=NULL):QLabel(text, parent){qDebug("from constructor");}~Label(){qDebug("from destructor");}
    };

本文中,我们从智能指针(smart pointer)角度继续考虑这个问题

智能指针

为了管理内存等资源,C++程序员通常采用RAII(Resource Acquisition Is Initialization)机制:在类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。

如果没有智能指针,程序员必须保证new对象能在正确的时机delete,四处编写异常捕获代码以释放资源,而智能指针则可以在退出作用域时(不管是正常流程离开或是因异常离开)总调用delete来析构在堆上动态分配的对象。

我们看看Qt家族的智能指针:

智能指针

 

引入

QPointer

Qt Object 模型的特性(之一)
注意:析构时不会delete它管理的资源

 

QSharedPointer

带引用计数

Qt4.5

QWeakPointer

 

Qt4.5

QScopedPointer

 

Qt4.6

QScopedArrayPointer

QScopedPointer的派生类

Qt4.6

QSharedDataPointer

用来实现Qt的隐式共享(Implicit Sharing)

Qt4.0

QExplicitlySharedDataPointer

显式共享

Qt4.4

   

std::auto_ptr

  

std::shared_ptr

std::tr1::shared_ptr

C++0x

std::weak_ptr

std::tr1::weak_ptr

C++0x

std::unique_ptr

boost::scoped_ptr

C++0x

注:

  • MSVC2010 和 GCC g++ 4.3 支持 C++0x
  • MSVC2008 sp1 及 GCC g++ 4.0 支持 tr1

有了这些东西,我们就可以很容易改造我们前面的例子了(只需改变一行):

std::auto_ptr<QLabel> label(new QLabel("Hello Dbzhang800!"));

根据你所用的Qt的版本,以及C++编译器的支持程度,你可以选用:

  • QScopedPointer
  • std::unique_ptr
  • QSharedPointer
  • std::shared_ptr
    • std::tr1::shared_ptr

QPointer

如何翻译呢?我不太清楚,保留英文吧。

  • The QPointer class is a template class that provides  guarded pointers   to QObjects.

  • 使用:一个guarded指针,QPointer<T> ,行为和常规的指针 T * 类似

  • 特点:当其指向的对象(T必须是QObject及其派生类)被销毁时,它会被自动置NULL.
    • 注意:它本身析构时不会自动销毁所guarded的对象
  • 用途:当你需要保存其他人所拥有的QObject对象的指针时,这点非常有用

一个例子

     QPointer<QLabel> label = new QLabel;label->setText("&Status:");...if (label)label->show();

如果在...部分你将该对象delete掉了,label会自动置NULL,而不会是一个悬挂(dangling)的野指针。

QPointer 属于Qt Object模型的核心机制之一,请注意和其他智能指针的区别。

std::auto_ptr

这个没多少要说的。

  • 不能让多个auto_ptr 指向同一个对象!(auto_ptr被销毁时会自动删除它指向的对象,这样对象会被删除多次)
    • 通过拷贝构造或赋值进行操作时,被拷贝的会自动变成NULL,复制所得的指针将获得资源的唯一所有权
  • 智能指针不能指向数组(因为其实现中调用的是delete而非delete[])
  • 智能指针不能作为容器类的元素。

在C++0x中,auto_ptr已经不建议使用,以后应该会被其他3个智能指针所取代。

QScopedPointer 与 std::unique_ptr

它们概念上应该是是一样的。下面不再区分:

这是一个很类似auto_ptr的智能指针,它包装了new操作符在堆上分配的动态对象,能够保证动态创建的对象在任何时候都可以被正确地删除。但它的所有权更加严格,不能转让,一旦获取了对象的管理权,你就无法再从它那里取回来。

无论是QScopedPointer 还是 std::unique_ptr 都拥有一个很好的名字,它向代码的阅读者传递了明确的信息:这个智能指针只能在本作用域里使用,不希望被转让。因为它的拷贝构造和赋值操作都是私有的,这点我们可以对比QObject及其派生类的对象哈。

用法 (来自Qt的manual):

考虑没有智能指针的情况,

 void myFunction(bool useSubClass){MyClass *p = useSubClass ? new MyClass() : new MySubClass;QIODevice *device = handsOverOwnership();if (m_value > 3) {delete p;delete device;return;}try {process(device);}catch (...) {delete p;delete device;throw;}delete p;delete device;}

我们在异常处理语句中多次书写delete语句,稍有不慎就会导致资源泄露。采用智能指针后,我们就可以将这些异常处理语句简化了:

 void myFunction(bool useSubClass){QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);QScopedPointer<QIODevice> device(handsOverOwnership());if (m_value > 3)return;process(device);}

另,我们一开始的例子,也是使用这两个指针的最佳场合了(出main函数作用域就将其指向的对象销毁)。

注意:因为拷贝构造和赋值操作私有的,它也具有auto_ptr同样的“缺陷”——不能用作容器的元素。

QSharedPointer 与 std::shared_ptr

QSharedPointer 与 std::shared_ptr 行为最接近原始指针,是最像指针的"智能指针",应用范围比前面的提到的更广。

QSharedPointer 与 QScopedPointer 一样包装了new操作符在堆上分配的动态对象,但它实现的是引用计数型的智能指针 ,可以被自由地拷贝和赋值,在任意的地方共享它,当没有代码使用(引用计数为0)它时才删除被包装的动态分配的对象。shared_ptr也可以安全地放到标准容器中,并弥补了std::auto_ptr 和 QScopedPointer 因为转移语义而不能把指针作为容器元素的缺陷。

QWeakPointer 与 std::weak_ptr

强引用类型的QSharedPointer已经非常好用,为什么还要有弱引用的 QWeakPointer?

QWeakPointer 是为配合 QSharedPointer 而引入的一种智能指针,它更像是 QSharedPointer 的一个助手(因为它不具有普通指针的行为,没有重载operator*和->)。它的最大作用在于协助 QSharedPointer 工作,像一个旁观者一样来观测资源的使用情况。

  • weak_ptr 主要是为了避免强引用形成环状。摘自msdn中一段话:
    • A cycle occurs when two or more resources controlled by shared_ptr objects hold mutually referencing shared_ptr objects. For example, a circular linked list with three elements has a head node N0; that node holds a shared_ptr object that owns the next node, N1; that node holds a shared_ptr object that owns the next node, N2; that node, in turn, holds a shared_ptr object that owns the head node, N0, closing the cycle. In this situation, none of the reference counts will ever become zero, and the nodes in the cycle will not be freed. To eliminate the cycle, the last node N2 should hold a weak_ptr object pointing to N0 instead of a shared_ptr object. Since the weak_ptr object does not own N0 it doesn't affect N0's reference count, and when the program's last reference to the head node is destroyed the nodes in the list will also be destroyed.
  • 在Qt中,对于QObject及其派生类对象,QWeakPointer有特殊处理。它可以作为QPointer的替代品
    • 这种情况下,不需要QSharedPointer的存在
    • 效率比 QPointer 高

QSharedDataPointer

这是为配合 QSharedData 实现隐式共享(写时复制 copy-on-write))而提供的便利工具。

Qt中众多的类都使用了隐式共享技术,比如QPixmap、QByteArray、QString、...。而我们为自己的类实现隐式共享也很简单,比如要实现一个 Employee类:

  • 定义一个只含有一个数据成员(QSharedDataPointer<EmployeeData>) 的 Employee 类

  • 我们需要的所有数据成员放置于 派生自QSharedData的 EmployeeData类中。

具体实现看 QSharedDataPointer 的Manual,此处略

QExplicitlySharedDataPointer

这是为配合 QSharedData 实现显式共享而提供的便利工具。

QExplicitlySharedDataPointer 和 QSharedDataPointer 非常类似,但是它禁用了写时复制功能。这使得我们创建的对象更像一个指针。

一个例子,接前面的Employee:

 #include "employee.h"int main(){Employee e1(1001, "Albrecht Durer");Employee e2 = e1;e1.setName("Hans Holbein");}

写时复制技术导致:e1和e2有相同的工号,但有不同名字。与我们期待的不同,显式共享可以解决这个问题,这也使得Employee本身更像一个指针。

补遗

先前竟未注意到官方的这两篇文章(这是失败):
  • http://labs.qt.nokia.com/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/
  • http://labs.qt.nokia.com/2009/08/21/introducing-qscopedpointer/
便看看google编码规范中对3个智能指针的建议:scoped_ptr
Straightforward and risk-free. Use wherever appropriate.
auto_ptr
Confusing and bug-prone ownership-transfer semantics. Do not use.
shared_ptr
Safe with const referents (i.e. shared_ptr<const T> ). Reference-counted pointers with non-const referents can occasionally be the best design, but try to rewrite with single owners where possible.

参考

  • Qt manual
  • Smart Pointers FAQ

  • The New C++:Smart(er) Pointers

  • http://en.wikipedia.org/wiki/Smart_pointer

  • C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍

  • 【C++Boost】智能指针的标准之争:Boost vs. Loki

  • http://www2.research.att.com/~bs/C++0xFAQ.html

  • http://msdn.microsoft.com/zh-cn/library/bb982126.aspx

  • http://www.codesynthesis.com/~boris/blog/2010/05/24/smart-pointers-in-boost-tr1-cxx-x0/

  • http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml

转载于:https://www.cnblogs.com/lanye/p/3564448.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/493457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Verilog HDL语言设计计数器+加法器

完成课本例题4.12&#xff0c;进行综合和仿真&#xff08;包括功能仿真和时序仿真&#xff09;&#xff0c;查看仿真结果&#xff0c;将Verilog代码和仿真波形图整理入实验报告。 功能文件&#xff1a; module shiyan1(out,reset,clk); input reset,clk; output reg[3:0] ou…

自动驾驶寒冬与否,关键看“芯”

来源&#xff1a;智车科技摘要&#xff1a;2018年&#xff0c;全世界瞩目的半导体行业大事件无疑是高通收购恩智浦了。虽然&#xff0c;最终这笔收购案以失败结尾&#xff0c;但高通的收购恩智浦的意图就是出自于拓展汽车芯片市场。智能汽车芯片的重要性也得以突显。前不久&…

如何知道自己的CPU支持SLAT

因为WP8 SDK发布&#xff0c;很多WP8的开发者们也开始陆续安装WP8的SDK的&#xff0c;然而安装WP8的SDK有很多软件和硬件的要求&#xff0c;其中有一个就是——要求CPU支持二级地址转换&#xff08;SLAT&#xff09;&#xff0c;如果CPU不支持二级地址转换的话&#xff0c;在电…

opencv基础知识及其一些例子

opencv官网 一.插值法 1.最近邻插值 上图可看出f(p)f(Q11),缺点可能出现明显的块状。 2.线性插值 3.双线性插值 通过线性插值确定R1和R2,最终在确定P 二.cv2.putText 图片添加文字 import cv2 img cv2.imread(caijian.jpg) font cv2.FONT_HERSHEY_SIMPLEXimgzi cv2.putT…

Verilog HDL语言设计实现过程赋值+译码器

完成课本例题6.11、6.12&#xff0c;进行综合和仿真&#xff08;功能仿真&#xff09;&#xff0c;查看综合和仿真结果&#xff0c;整理入实验报告。 6.11 module shiyan21(in,clk,out1,out2); input clk,in; output out1,out2; reg out1,out2; always (posedge clk) beg…

【工业4.0】深度报告:独家解密工业4.0真正图谋?跟踪软件帝国的十年

来源&#xff1a;知识自动化要理解工业4.0&#xff0c;就避不开对西门子的研究&#xff1b;而要看懂西门子&#xff0c;不要去要看它的硬件&#xff0c;而要去看它的软件。数字化工厂只是水中花&#xff0c;真正的花朵不在你眼前&#xff0c;而在你身头。德国安贝格和成都的数字…

检测系列--RCNN系列

一.RCNN 框架&#xff1a; 1.selective search 2,区域预处理&#xff0c;尺寸缩放到227227 3.利用Alexnet(去掉最后分类层&#xff0c;4096维向量)&#xff0c;做特征提取&#xff0c;一个物体一个SVM分类&#xff0c;(当时认为SVM比softmax分类好)bounding box回归 4.正负样本…

Verilog HDL语言设计实现D触发器+计数器

分别采用结构描述和行为描述方式设计一个基本的D触发器&#xff0c;在此基础上&#xff0c;采用结构描述的方式&#xff0c;用8个D触发器构成一个8位移位寄存器。进行功能仿真&#xff0c;查看结果&#xff0c;把上述内容整理到实验报告。&#xff08;1&#xff09;行为描述:单…

使用ant自动生成签名的apk

eclipse打包apk发布&#xff0c;每次都要输入签名的密码&#xff0c;而且打包的过程很长。特别是同一个程序要配置不同的标识打包&#xff0c;会很耗时&#xff0c;结合ant的使用&#xff0c;可以一键打包&#xff0c;会方便很多。 1.ant 官网可下载 http://ant.apache.org/ 或…

2018年全球十大新兴技术:细胞植入人体、营养人造肉……你想试试吗?

来源&#xff1a;光明日报摘要&#xff1a;在不久的将来&#xff0c;技术革新将如何改变我们的生活&#xff1f;人工智能将大幅提升新药物和新材料的开发速度&#xff1b;新型诊断工具将打造更先进的个性化医疗&#xff1b;如果你生病了&#xff0c;医生将可以在你体内植入活细…

检测系列--YOLO系列

开头语&#xff1a;RCNN系列&#xff0c;需要区域候选框&#xff0c;即便最后是多任务损失函数&#xff0c;但回归和分类各是一块是很明显的&#xff0c;而yolo要把分类问题转换成回归&#xff0c;这样的話就全是回归。 一.yolo v1 1,介绍&#xff0c;此时输入size要一致448*…

Verilog HDL语言实现ROM、RAM+有限状态机

利用MegaWizard实现创建RAM和ROM。&#xff08;1&#xff09;建立1个32单元8bit的RAM&#xff0c;并将0-31填入该RAM&#xff1b;&#xff08;2&#xff09;建立1个32单元8bit的ROM&#xff0c;建立.mif文件填入数据&#xff0c;并读出来显示。 (1)、RAM 功能代码: module sh…

UVA11427概率期望+独立重复事件

1 /*UVA11427*/2 /*概率期望:3 独立重复事件A(p,n):4 p&#xff1a;一件事情发生的概率为p5 n:最多重复n次6 要求&#xff1a;1、q成功次数/实验次数>p 结束实验&#xff1b;7 所求&#xff1a;n次实验后&#xff0c;q一直小于等于p8 9 初始思考&#xff1a; 10 ans1-补集&a…

重磅!亚马逊将在2019年全面弃用Oracle数据库

来源&#xff1a;AI 前线摘要&#xff1a;11 月 29 日&#xff0c;AI 前线获悉&#xff0c;亚马逊 AWS 首席执行官 Andy Jassy 在正在美国拉斯维加斯召开的 AWS re&#xff1a;Invent 2018 中表示&#xff1a;到 2019 年底&#xff0c;亚马逊将全面放弃使用 Oracle 数据库&…

数字图像处理实验6图像编码

一、实验目的 &#xff08;1&#xff09;了解图像编码的目的及意义&#xff0c;加深对图像编码的感性认识。 &#xff08;2&#xff09;熟练掌握哈夫曼编码的实现与应用。 &#xff08;3&#xff09;掌握行程长度编码的实现与应用&#xff0c;尤其是BMP和PCX文件的行程长度编…

机器人日行十万步却无需动力源!究竟如何完美的机械结构让你开始怀疑人身...

来源&#xff1a;机器人大讲堂摘要&#xff1a;上图这个机器人可不简单&#xff0c;它是世界纪录的保持者&#xff0c;目前最新的纪录是连续步行27小时&#xff0c;总长72公里&#xff08;相当于十万步还要多&#xff09;。而最最关键的是&#xff0c;它完全凭借自己完美的机械…

数字图像处理实验5图像复原

一、实验目的 &#xff08;1&#xff09;了解图像复原的目的及意义&#xff0c;加深对图像复原理论的认识。 &#xff08;2&#xff09;掌握维纳滤波复原基本原理。 &#xff08;3&#xff09;掌握约束最小二乘方复原方法。 &#xff08;4&#xff09;掌握盲解卷积复原方法…

MVVM模式的一个小例子

使用SilverLight、WPF也有很长时间了&#xff0c;但是知道Binding、Command的基本用法&#xff0c;对于原理性的东西&#xff0c;一直没有深究。如果让我自己建一个MVVM模式的项目&#xff0c;感觉还是无从下手&#xff0c;最近写了一个小例子&#xff0c;贴上代码&#xff0c;…

实现两个点集的欧式距离和cos距离和索引值寻找(含有两种解法,for循环和矩阵操作)

一.计算欧式距离 1&#xff0c;直接for循环 两个点集points1&#xff0c;points2&#xff0c;用dist来存储距离 points1np.array([[1,2],[3,4]]) points2 np.array([[5, 6],[7,8]]) dist np.zeros(shape[points1.shape[0],points2.shape[0]]) for i in range(points1.sha…

数字图像处理实验四图像频域增强

一、实验目的 &#xff08;1&#xff09;了解图像增强的目的及意义&#xff0c;加深对图像增强的感性认识&#xff0c;巩固所学的图像增强的理论知识和相关算法。 &#xff08;2&#xff09;熟练掌握低通、高通、带通、同态滤波器的使用方法&#xff0c;明确不同性质的滤波器…