STL中的智能指针auto_ptr可以实现简单的内存自动回收,防止内存泄漏(memory leakage)。auto_ptr实际是一个类,在该类析构时自动调用delete,从而达到了内存回收的效果。但是,由于同一个指针同一时刻只能被一个auto_ptr占用,如果采用赋值操作(=)或者拷贝构造函数调用,就会发生所有权转移,例如:
auto_ptr<int> p(new int(0));
auto_ptr<int> q;
此时,p拥有指向一个int的指针,q的指针为空。如果执行q=p;则,p指向空,q指向int;但是,这样所有权转换的问题同样发生在参数传递中,例如
void foo(auto_ptr<int> t);
如果调用 foo(p);那么p就丢失了指针,所以一个解决方法是用引用,例如:
void foo1(auto_ptr<int>& t);
void foo2 (const auto_ptr<int>& t);
两者都是可以的,不过foo1非常不安全,因为在函数里面很容易通过类似赋值的操作使t丢失指针,而foo2不会。例如
void foo2(const auto_ptr<int>& t)
{
auto_ptr<int> m; m=t;
}
会发生编译错误,从而避免灾难的发生。但随之又出现一个很大的问题,就是auto_ptr类的拷贝构造函数,或者赋值函数。最理想的情况是这样(如果能成功,就不会有别的什么问题):
auto_ptr(const auto_ptr& rhs):ap(rhs.release()){}
但由于上述的原因,会发生编译错误(因为调用了release(),而release()会改变成员变量,不再是const)。所以只能去掉const,变为
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代替模板参
struct auto_ptr_ref
{
int* p;
auto_ptr_ref(int *t):p(t){}
};
然后在auto_ptr类中增加了以下函数
auto_ptr(auto_ptr_ref rhs):ap(rhs.p){}
auto_ptr& operator=(auto_ptr_ref rhs){reset(rhs.p); return *this;}
operator auto_ptr_ref(){return auto_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,任务完成。
其实说白了问题很简单,因为构造函数不能接受右值,则取中间左值=右值, 然后再让函数接受中间左值。 而这一系列过程正是利用编译器能够自动进行类型转换而完成的。
本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2008/08/19/1271700.html,如需转载请自行联系原作者
微信关注我们
原文链接:https://yq.aliyun.com/articles/338826
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
相关文章
发表评论
资源下载
更多资源Mario,低调大师唯一一个Java游戏作品
马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。
Oracle Database,又名Oracle RDBMS
Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。
Java Development Kit(Java开发工具)
JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
Sublime Text 一个代码编辑器
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。