STL中的智能指针auto_ptr可以实现简单的内存自动回收,防止内存泄漏(memory leakage)。auto_ptr实际是一个类,在该类析构时自动调用delete,从而达到了内存回收的效果。但是,由于同一个指针同一时刻只能被一个auto_ptr占用,如果采用赋值操作(=)或者拷贝构造函数调用,就会发生所有权转移,例如:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->auto_ptr<int>p(newint(0));
auto_ptr<int>q;
此时,p拥有指向一个int的指针,q的指针为空。如果执行q=p;则,p指向空,q指向int;但是,这样所有权转换的问题同样发生在参数传递中,例如
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->voidfoo(auto_ptr<int>t);
如果调用 foo(p);那么p就丢失了指针,所以一个解决方法是用引用,例如:
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->voidfoo1(auto_ptr<int>&t);
voidfoo2(constauto_ptr<int>&t);
两者都是可以的,不过foo1非常不安全,因为在函数里面很容易通过类似赋值的操作使t丢失指针,而foo2不会。例如
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->voidfoo2(constauto_ptr<int>&t)
{
auto_ptr<int>m;m=t;
}
会发生编译错误,从而避免灾难的发生。但随之又出现一个很大的问题,就是auto_ptr类的拷贝构造函数,或者赋值函数。最理想的情况是这样(如果能成功,就不会有别的什么问题):
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->auto_ptr(constauto_ptr&rhs):ap(rhs.release()){}
但由于上述的原因,会发生编译错误(因为调用了release(),而release()会改变成员变量,不再是const)。所以只能去掉const,变为
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->auto_ptr(auto_ptr&rhs):ap(rhs.release()){}
这样可以编译成功,而且往往也能正确运行,但是唯一的问题是: 当rhs为右值时会出现问题。
为了简化问题,先假设拷贝构造函数什么都不做,即:
auto_ptr(auto_ptr& rhs){}
那么,如果有 auto_ptr<int> p(new int(10)),执行 auto_ptr<int> q(p),不会有任何问题,因为p是左值。但如果执行auto_ptr<int> q(auto_ptr<int>(new int(10))) ,则会发生编译错误,因为auto_ptr<int>(new int(10)) 是右值,对右值的引用只能是常引用,也就是"const auto_ptr& rhs"的形式。但这里要注意的是,刚才那段代码用VC编译没有任何问题,并且可以顺利运行,但是用GCC之类的标准c++就不能顺利编译。
在VC中auto_ptr<int>& p=auto_ptr<int>(new int(0)) 是合法的,但在标准C++中是不合法的,只有const auto_ptr<int>& p=auto_ptr<int>(new int(0)) 才是合法的,也即在标准C++中,对右值的引用只能是常引用。所以说,要在标准C++中实现 auto_ptr<int> p(auto_ptr<int>(new int(0))) 就变得不可能了,因为如上所说,拷贝构造函数是这样的形式:auto_ptr(auto_ptr<T>& rhs):ap(rhs.release()){}
但是不能把右值传到一个非常引用中。但毕竟有聪明的人能想到解决办法,利用代理类( proxy class)声明如下结构,为了方便,我用int代替模板参
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->structauto_ptr_ref
{
int*p;
auto_ptr_ref(int*t):p(t){}
};
然后在auto_ptr类中增加了以下函数
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->auto_ptr(auto_ptr_refrhs):ap(rhs.p){}
auto_ptr&operator=(auto_ptr_refrhs){reset(rhs.p);return*this;}
operatorauto_ptr_ref(){returnauto_ptr_ref(release());}
之后,如果在标准C++有以下调用(VC中也会按照这个步骤调用,虽然没有auto_ptr_ref它也能直接调用)
auto_ptr<int> p(auto_ptr<int>(new int(0)))
便可以成功,过程如下:
1. 构造临时对象 auto_ptr<int>(new int(0))
2. 想将临时对象通过拷贝构造函数传给p,却发现没有合适的拷贝构造函数,因为只有auto_ptr(auto_ptr& rhs)这个不能用,又没有auto_ptr(const auto_ptr& rhs) (因为用了在所有权转移中会出错)!
3. 编译器只能曲线救国,看看类型转换后能不能传递。
4. 由于我们定义了 operator auto_ptr_ref() 所以编译器自然就可以试一下转为 auto_ptr_ref类型。
5. 编译器猛然间发现,我们定义了 auto_ptr(auto_ptr_ref rhs):ap(rhs.p){} 的构造函数,可以传递。
6. 顺利构造p,任务完成。
其实说白了问题很简单,因为构造函数不能接受右值,则取中间左值=右值, 然后再让函数接受中间左值。 而这一系列过程正是利用编译器能够自动进行类型转换而完成的。
分享到:
相关推荐
C++Primer中文第三版(C++从入门到精通)第一章的读书笔记,主要是C++程序、预处理器指示符、iostream库等的基础知识点读书笔记。
本源代码既有多线程的使用,VC的各种控件的使用,以及动态连接库,ActiveX控件,网络编程,数据库编程,以及最后的一个整体大程序,KTV点歌系统等等
Boost是一个功能强大、构造精巧、跨平台、开源并且完全免费的C++程序库,有着“C++‘准’标准库”的美誉。 Boost由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串...
本书以 Visual C++ 6.0为平台,结合 Visual C++ 6.0和MFC应用程序设计框架的最新规范,从基本的操作和技巧入手,以恰当的实例为导向,对实例代码进行层层图解的方式,由浅入深地介绍了 Visual C++开发的基本理论知识...
它是一种将程序库名称封装起来的方法,它提高了程序的性能和可靠性。 4.动态内存分配的一般格式为: 指针名 = new 结构名; delete 指针名; 5.引用的声明格式为: 数据类型 & 别名 = 对象名; 6.引用通常用于函数的...
该复习文档是本人根据谭浩强老师的《C++程序设计》、邓俊辉的《数据结构(C++语言版)》和CSDN博客上的众多文章总结而成的。感谢博客上各位大佬的总结,使我在复习课本的同时补充了很多其他方面的关键知识,如C++...
NULL 博文链接:https://hyjiang1989.iteye.com/blog/1821527
Windows编程 C++ DLL编程 学习笔记(一)静态链接库的创建和使用 本文件中只有程序,不含笔记和注释,笔记和注释请到空间察看http://giddyandyang.spaces.live.com/
Windows编程 C++ DLL编程 学习笔记 (二)动态链接库的创建 动态调用 静态调用 本文件中只有程序,不含笔记和注释,笔记和注释请到空间察看http://giddyandyang.spaces.live.com/
学习韦东山老师的4412开发板视频,做了点笔记,发出来跟大家分享一下这个学习的过程,如发现说的有误的地方,还请指出,谢谢!
源码配套博文 《【Visual C++】游戏开发笔记三十七 浅墨DirectX提高班之五 顶点缓存的红颜知己:索引缓存的故事 》 ,文章地址为http://blog.csdn.net/zhmxy555/article/details/8304741, 点击debug下的exe文件...
qss 样式表,本程序所有窗体、控件的样式都由qss设计 signal\slot 控件、窗体间通信,事件处理 QThread 异步处理 iconfont 阿里巴巴矢量图标库,主要用于按钮及标签上图标等显示 sqlite 存储数据库
【Visual C++】游戏开发笔记之【浅墨DirectX提高班】系列博文 配套详细注释源码之十 源码配套博文 《【Visual C++】游戏开发笔记四十二 浅墨DirectX教程之十 游戏输入控制利器:DirectInput专场》 ,文章地址为...
源码的配套博文是 《【Visual C++】游戏开发笔记四十七 浅墨DirectX教程十五 翱翔于三维世界:摄像机的实现》 ,文章地址为http://blog.csdn.net/zhmxy555/article/details/8657656, 点击Debug下的exe文件可以...
源码的配套博文是 《【Visual C++】游戏开发笔记四十八 浅墨DirectX教程十六 三维地形系统的实现》 ,文章地址为http://blog.csdn.net/zhmxy555/article/details/8685546, 点击Release文件夹下的exe文件可以直接...
源码的配套博文是 《【Visual C++】游戏开发笔记四十六 浅墨DirectX教程十四 模板测试与镜面特效专场》 ,文章地址为http://blog.csdn.net/zhmxy555/article/details/8632184, 点击Release下的exe文件可以直接...
Vim 通常被称为“程序员的编辑器”,是一种老式的文本编辑器,主要涉及效率,灵活性和定制性。如果您是 Vim 的爱好者,并且当前正在...有关该项目的更多信息以及详细的文档部分,请参阅应用程序的官方 GitHub 存储库。
个人学习笔记 , 涵盖C , C++, Linux驱动, Linux内核, 嵌入式, 数据结构, 算法, QT, Android安卓, 音视频, 物联网 , 正在逐步更新 , 使用的typora编辑 , 大家可以使用 typora 打开查看 , 床图为 gitee Linux项目是一...
Python由荷兰数学和计算机科学研究学会的吉多·范罗苏姆于1990年代初设计,作为一门叫做ABC语言的替代品。 [1] Python提供了高效的高级数据...Python丰富的标准库,提供了适用于各个主要系统平台的源码或机器码。 [4]
Qt [1] 是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象...