转浅析autoptrWord文件下载.docx
- 文档编号:21707358
- 上传时间:2023-01-31
- 格式:DOCX
- 页数:13
- 大小:20.13KB
转浅析autoptrWord文件下载.docx
《转浅析autoptrWord文件下载.docx》由会员分享,可在线阅读,更多相关《转浅析autoptrWord文件下载.docx(13页珍藏版)》请在冰豆网上搜索。
auto_ptr的做法是“所有权转移”,即拷贝或赋值的源对象将失去对“裸”指针的所有权,所以,与一般拷贝构造函数,赋值函数不同,auto_ptr的拷贝构造函数,赋值函数的参数为引用而不是常引用(constreference).当然,一个auto_ptr也不能同时拥有两个以上的“裸”指针,所以,拷贝或赋值的目标对象将先释放其原来所拥有的对象。
这里的注意点是:
1)因为一个auto_ptr被拷贝或被赋值后,其已经失去对原对象的所有权,这个时候,对这个auto_ptr的提领(dereference)操作是不安全的。
如下:
ap2=ap1;
cout<
<
*ap1;
//错误,此时ap1只剩一个null指针在手了
这种情况较为隐蔽的情形出现在将auto_ptr作为函数参数按值传递,因为在函数调用过程中在函数的作用域中会产生一个局部对象来接收传入的auto_ptr(拷贝构造),这样,传入的实参auto_ptr就失去了其对原对象的所有权,而该对象会在函数退出时被局部auto_ptr删除。
如下:
voidf(auto_ptr<
ap){cout<
*ap;
ap1(newint(0));
f(ap1);
//错误,经过f(ap1)函数调用,ap1已经不再拥有任何对象了。
因为这种情况太隐蔽,太容易出错了,所以auto_ptr作为函数参数按值传递是一定要避免的。
或许大家会想到用auto_ptr的指针或引用作为函数参数或许可以,但是仔细想想,我们并不知道在函数中对传入的auto_ptr做了什么,如果当中某些操作使其失去了对对象的所有权,那么这还是可能会导致致命的执行期错误。
也许,用constreference的形式来传递auto_ptr会是一个不错的选择。
2)我们可以看到拷贝构造函数与赋值函数都提供了一个成员模板在不覆盖“正统”版本的情况下实现auto_ptr的隐式转换。
如我们有以下两个类
classbase{};
classderived:
publicbase{};
那么下列代码就可以通过,实现从auto_ptr<
derived>
到auto_ptr<
base>
的隐式转换,因为derived*可以转换成base*类型
apbase=auto_ptr<
(newderived);
3)因为auto_ptr不具有值语义(valuesemantic),所以auto_ptr不能被用在stl标准容器中。
所谓值语义,是指符合以下条件的类型(假设有类A):
Aa1;
Aa2(a1);
Aa3;
a3=a1;
那么
a2==a1,a3==a1
很明显,auto_ptr不符合上述条件,而我们知道stl标准容器要用到大量的拷贝赋值操作,并且假设其操作的类型必须符合以上条件。
3提领操作(dereference)
提领操作有两个操作,一个是返回其所拥有的对象的引用,另一个是则实现了通过auto_ptr调用其所拥有的对象的成员。
如:
structA
voidf();
A>
apa(newA);
(*apa).f();
apa->
f();
当然,我们首先要确保这个智能指针确实拥有某个对象,否则,这个操作的行为即对空指针的提领是未定义的。
4辅助函数
1)get用来显式的返回auto_ptr所拥有的对象指针。
我们可以发现,标准库提供的auto_ptr既不提供从“裸”指针到auto_ptr的隐式转换(构造函数为explicit),也不提供从auto_ptr到“裸”指针的隐式转换,从使用上来讲可能不那么的灵活,考虑到其所带来的安全性还是值得的。
2)release,用来转移所有权
3)reset,用来接收所有权,如果接收所有权的auto_ptr如果已经拥有某对象,必须先释放该对象。
5特殊转换
这里提供一个辅助类auto_ptr_ref来做特殊的转换,按照标准的解释,这个类及下面4个函数的作用是:
使我们得以拷贝和赋值non-constauto_ptrs,却不能拷贝和赋值constauto_ptrs.我无法非常准确的理解这两句话的意义,但根据我们观察与试验,应该可以这样去理解:
没有这些代码,我们本来就可以拷贝和赋值non-const的auto_ptr和禁止拷贝和赋值const的auto_ptr的功能,只是无法拷贝和赋值临时的auto_ptr(右值),而这些辅助代码提供某些转换,使我们可以拷贝和赋值临时的auto_ptr,但并没有使const的auto_ptr也能被拷贝和赋值。
ap1=auto_ptr<
(newint(0));
(newint(0))是一个临时对象,一个右值,一般的拷贝构造函数当然能拷贝右值,因为其参数类别必须为一个constreference,但是我们知道,auto_ptr的拷贝函数其参数类型为reference,所以,为了使这行代码能通过,我们引入auto_ptr_ref来实现从右值向左值的转换。
其过程为:
1)ap1要通过拷贝auto_ptr<
(newint(0))来构造自己
2)auto_ptr<
(newint(0))作为右值与现有的两个拷贝构造函数参数类型都无法匹配,也无法转换成该种参数类型
3)发现辅助的拷贝构造函数auto_ptr(auto_ptr_ref<
T>
rhs)throw()
4)试图将auto_ptr<
(newint(0))转换成auto_ptr_ref<
5)发现类型转换函数operatorauto_ptr_ref<
Y>
()throw(),转换成功,从而拷贝成功。
从而通过一个间接类成功的实现了拷贝构造右值(临时对象)
同时,这个辅助方法不会使constauto_ptr被拷贝,原因是在第5步,此类型转换函数为non-const的,我们知道,const对象是无法调用non-const成员的,所以转换失败。
当然,这里有一个问题要注意,假设你把这些辅助转换的代码注释掉,该行代码还是可能成功编译,这是为什么呢?
debug一下,我们可以发现只调用了一次构造函数,而拷贝构造函数并没有被调用,原因在于编译器将代码优化掉了。
这种类型优化叫做returnedvalueoptimization,它可以有效防止一些无意义的临时对象的构造。
当然,前提是你的编译器要支持returnedvalueoptimization。
auto_ptr的使用及其源码注释
/**
ModuleName:
main.cpp
Description:
继承标准异常类创建了自己的异常类CatException
创建一个类Cat
使用了auto_ptr模板
Author:
Harite.K@
Created:
MinGW32_3.4.4&
&
C-Free4.0beta1
LastChange:
2006/09/17
*/
#include<
memory>
string>
cstring>
iostream>
exception>
cstdio>
usingnamespacestd;
//异常类
classCatException:
publicexception
public:
CatException(conststring&
errormsg)throw()
{
__errormsg=errormsg;
}
~CatException()throw()
constchar*what()constthrow()
return__errormsg.c_str();
private:
string__errormsg;
};
//
//一个简单的自定义类型Cat
classCat
//构造
Cat(conststring&
name,intage)
if(name.empty())
throwCatException("
Exception:
猫咪姓名不能为空!
"
);
if(age<
=0)
猫咪年龄只能为正!
__age=age;
__name=newchar[name.length()+1];
strcpy(__name,name.c_str());
#ifdefNEEDDEBUG
cout<
"
DEBUG:
猫咪已被成功创建(年龄:
<
__age<
名字:
__name<
)"
endl;
#endif
Cat(constchar*name,intage)
if(strlen(name)==0)
__name=newchar[strlen(name)+1];
strcpy(__name,name);
Cat(constCat&
ocat)
delete[]__name;
__name=newchar[strlen(ocat.__name)+1];
strcpy(__name,ocat.__name);
//方法
voidBeep()const
猫咪"
叫了。
intGetAge()const
return__age;
const
char*GetName()const
return__name;
voidSetName(string&
name)
voidSetName(char*name)
voidSetAge(intage)
//重载操作符
Cat&
operator=(constCat&
return*this;
//析构
~Cat()
猫咪将被删除(年龄:
int__age;
char*__name;
intmain(intargc,char*argv[])
try
auto_ptr<
Cat>
mycatAptr(newCat("
Bother"
2));
//此时au_mycat_a便俘获了指向新建Cat对象的指针
//可以使用au_mycat_a来对对象进行操作了,比如“叫”
mycatAptr->
Beep();
mycatBptr;
mycatBptr=mycatAptr;
//此时,mycatAptr把控制权交给了mycatBptr
mycatBptr->
//此时如果再次调用au_mycat_a->
Beep()就会产生错误。
mycatAptr.reset(mycatBptr.release());
//mycatAptr重启掌控对象,mycatBptr转让了对对象的控制
//此时如果mycatBptr->
Beep()将会出错。
Cat*tmp=mycatAptr.release();
//mycatAptr也拒绝了对对象的控制,release()返回指向被放弃的对象的指针(对象并没有被删除)
tmp->
//此时mycatAptr已经不能在调用Beep()函数了。
catch(CatException&
ce)
ce.what()<
return0;
这是在mingw32-3.4.4下找到的源文件。
它被包含在std空间内。
//这个模板结构是为了让auto_ptr成为函数返回值
template<
typename_Tp1>
structauto_ptr_ref
_Tp1*_M_ptr;
explicit
auto_ptr_ref(_Tp1*__p):
_M_ptr(__p){}
};
typename_Tp>
classauto_ptr
_Tp*_M_ptr;
//真正存储的数据,一个指针型
typedef_Tpelement_type;
//数据类型
//这种构造直接将指针赋值给_M_ptr
auto_ptr(element_type*__p=0)throw():
//拷贝构造函数,会先将参数__a作废,然后使对象捕获__a原本指向的目标
auto_ptr(auto_ptr&
__a)throw():
_M_ptr(__a.release()){}
//带模板的转化函数,同上。
template<
auto_ptr(auto_ptr<
_Tp1>
//这个=号赋值也会使__a作废,原因在此,注意。
auto_ptr&
operator=(auto_ptr&
__a)throw()
reset(__a.release());
//模板例程,效果同上。
operator=(auto_ptr<
//当auto_ptr对象被销毁时,他无情的销毁了_M_ptr
~auto_ptr(){delete_M_ptr;
//此处要注意防止_M_ptr为空!
element_type&
operator*()constthrow()
_GLIBCXX_DEBUG_ASSERT(_M_ptr!
=0);
return*_M_ptr;
//同上
element_type*
operator->
()constthrow()
return_M_ptr;
//返回_M_ptr,指针类型
get()constthrow(){return_M_ptr;
//将对象对_M_ptr的控制拿掉,返回另一个对它的指向
release()throw()
element_type*__tmp=_M_ptr;
_M_ptr=0;
//置0
return__tmp;
//如果__p和_M_ptr不一样的话,删除原_M_ptr内容,然后让其指向__p
void
reset(element_type*__p=0)throw()
if(__p!
=_M_ptr)
delete_M_ptr;
_M_ptr=__p;
//为了匹配类似形式
//auto_ptr<
Derived>
func_returning_auto_ptr(.....);
auto_ptr(auto_ptr_ref<
element_type>
__ref)throw()
:
_M_ptr(__ref._M_ptr){}
Base>
ptr=func_returning_auto_ptr(.....);
operator=(auto_ptr_ref<
if(__ref._M_ptr!
=this->
get())
_M_ptr=__ref._M_ptr;
//匹配两种转化形式
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 浅析 autoptr