智能指针-----》auto_ptr
发布日期:2021-05-07 09:16:09 浏览次数:16 分类:技术文章

本文共 4875 字,大约阅读时间需要 16 分钟。

智能指针:

c11里面的四个智能指针:auto_ptr,unique_ptr,shared_ptr,weak_ptr其中后三个是c11支持的,并且第一个已经被c11弃用。本博客主要讲auto_ptr,后面会持续更新其他智能指针。

c98中auto_ptr所做的事情就是动态分配对象以及当对象不再需要时自动执行清理。

举例:
以下不使用auto_ptr的函数就有可能发生内存泄漏:

void fun(){   	Object* op = new Object(10);	cout << op->Value() << endl;	if (op->Value() == 10)	{   		return;//内存泄漏	}	delete op;}

使用auto_ptr指针很好的避免了内存泄漏:函数结束的时候,auto_ptr调用析构函数,可以释放资源。

void fun(){   	auto_ptr pObja(new Object(10));	if (pObja->Value() == 10)	{   		cout << pObja->Value() << endl;		return;	}	return;}

auto_ptr 源码:

#include 
#include
using namespace std;namespace wwn{ template
class auto_ptr { private: T* _Ptr; bool _Owns;//使用权 public: typedef T element_type; explicit auto_ptr(T* p = nullptr) :_Owns(p!=nullptr),_Ptr(p){ } auto_ptr(const auto_ptr
& _Y) :_Owns(_Y._Owns), _Ptr(_Y.release){ } //错误:按照设计的先后顺序初始化,所以会先执行_ptr(_Y.release) auto_ptr& operator=(const auto_ptr
& _Y) { if (this != &_Y) { if (_Ptr != _Y.get()) { if (_Owns) delete _Ptr; _Owns = _Y._Owns; } else if(_Y._Owns) { _Owns = true; } _Ptr = _Y.release(); } return *this; } ~auto_ptr() { if (_Owns) { delete _Ptr; } _Ptr = NULL; } void reset(T* p = NULL) { if (_Owns) { delete _Ptr; } _Ptr = p; } T* get() const { return _Ptr; } T & operator*() const { return (*get()); } T* operator->()const { return get(); } T* release()const { T* tmp = NULL; if (_Owns) { ((auto_ptr
*)this)-> _Owns = false; tmp = _Ptr; ((auto_ptr
*)this)->_Ptr = NULL; } return tmp; } };}class Object{ private: int value;public: Object(int x=0):value(x){ } ~Object(){ } int& Value() { return value; } const int& Value()const { return value; } void Print() const{ cout << value << endl; }};void fun1(){ //vector
>vec; //错误,绝对不可以这样写 vector
vec; vec.push_back(new int(10)); vec.push_back(new int(20));}void fun(){ wwn::auto_ptr
oap(new Object(10)); cout << oap->Value() << endl; oap->Value() = 100; cout << oap->Value() << endl; wwn::auto_ptr
iap(new int(10)); wwn::auto_ptr
ibp; ibp = iap;}int main(){ fun(); return 0;}

注意:oap.{ get() ; operator() ; operator() ; ~auto_ptr() ; _ptr} 智能指针 . 后面跟的是智能指针自己的方法以及成员。

在这里插入图片描述

oap->{ Value() ; value ; ~Object() } 智能指针-> 后面跟的是智能指针所指对象的属性和方法。

在这里插入图片描述

opa->Print();(*opa).Print();//两个是等价的

auto_ptr的使用以及弃用原因

  1. 构造函数与析构函数
    auto_ptr在构造时获取对某个对象的所有权,在析构时时释放该函数
    我们可以这样使用auto_ptr来提高代码的安全性
int* p=new int(0);auto_ptr
ap(p);

这样就不必关心何时是释放p,也不用担心发生异常会有内存泄露。

弃用原因
1)因为auto_ptr析构的时候会删除他所拥有的对象,所以不同的auto_ptr不能指向同一个对象。如下:

int* p=new int(0);auto_ptr
ap1(p);auto_ptr
ap2(p);

这样在ap1和ap2在析构时都会去删除p,两次删除同一个对象的行为在c++标准中是未定义的。

2)

String *str=new String[10];auto_ptr
ap(str);

考虑以上情况,auto_ptr在析构函数中删除针织用的是delete,而不是delete[],所以我们不应该用auto_ptr来管理一个数组指针。

3)构造函数的explicit关键字有效阻止从一个“裸”指针隐式转换成auto_ptr;
2. 拷贝构造与赋值
与引用计数型指针不同,auto_ptr要求其对“裸”指针的完全占有。也就是一个“裸”指针只能同一时刻只能被一个auto_ptr拥有,所以在拷贝构造或者赋值操作时,要做的事所有权的转移。即就是使源对象失去所有权,所以拷贝构造函数和赋值函数的参数为引用而不是常引用。当然,因为一个auto_ptr同一个时刻只能指向一个裸指针,所以应该先释放原来拥有的对象。
弃用原因
1)因为一个auto_ptr被拷贝或者赋值后,失去了对原对象的所有权,这个时候,对这个auto_ptr的提领操作是不安全的。如下:

int *p=new int(0);auto_ptr
ap1(p);auto_ptr
ap2=ap1;cout<<*ap1;//错误,此时ap1已经失去对p指针的拥有权

还有一种较为隐蔽的情形,如下:

void fun(auto_ptr
ap){ cout<<*ap;}auto_ptr
ap1(new int(0));fun(ap1);cout<<*ap1;//错误,调用fun函数的时候将其对象的拥有权转移给函数的形参ap,所以此时ap1不再拥有对象

该情况太隐蔽,将auto_ptr作为函数参数按值传递一定是要避免的,因为无法预料函数会对auto_ptr做什么,如果在该过程中失去了对对象的拥有权,这可能导致致命的执行期错误。

2)可以看到拷贝构造函数和赋值函数都提供了一个成员模板在不覆盖“正统”版本的情况下实现auto_ptr的隐式转换,如下:

class Object{   };class Base:public Object{   };

那么下面代码就可以实现从auto_ptr到auto_ptr的隐式转换。

auto_ptr obj=auto_ptr(new Base);

3)因为auto_ptr不具有值语义,所以auto_ptr不能被用在stl标准容器中。

举例如下:

vector
> vec;vec.push_back(auto_ptr(new Object(10)));vec.push_back(auto_ptr(new Object(20)));auto_ptr apobj=vec.back();//将vec里面最后一个指针的拥有权转移给apobj,即此时20所在的指针的拥有权转移到apobj指针vec.size();//此时vec的大小仍然为2for(auto &x:vec){ (*x).Print();//打印20的时候会报错 x->Print;}
  1. 提领操作
    提领操作有两个操作,一个是返回其所拥有的对象的引用,另一个是实现通过auto_ptr调用其所拥有对象的成员,如下:
class Base{       void fun(){   };}auto_ptr ap(new Base());(*ap).fun();ap->fun();

首先我们要确保这个智能指针确实拥有某个对象,否则,这个操作的行为即对空指针的提领是未定义的。

使用auto_ptr的注意事项

  • auto_ptr不能指向数组
  • auto_ptr不能共享所有权
  • auto_ptr不能通过赋值操作来初始化
  • auto_ptr不能作为容器来使用
  • auto_ptr不能作为容器的成员
  • 不能把一个原生指针给两个智能指针对象管理
上一篇:智能指针2-----》unique_ptr
下一篇:linux---------》进程创建:fork与vfork

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2025年04月10日 05时42分38秒