【C++】智能指针(一)---auto_ptr指针

智能指针的思想

1、智能指针的引出
在代码编写过程中,我们不可避免的带入一些bug,某个指针过期失效后,并没有及时将对应的内存释放,这样就造成了内存泄漏,如何避免类似问题的出现,除了代码编写过程中注意,其次可以通过智能指针帮我们做一些类似的工作。这就是智能指针的引出。
2、智能指针的思想
将基本类型指针封装为类对象指针(这个类肯定是个模板,以适应不同基本类型的需求),并在析构函数里编写delete语句删除指针指向的内存空间。

智能指针的分类

智能指针分为四种:
1、auto_ptr(C++98)
2、unique_ptr(C++11)
3、shared_ptr(C++11)
4、weak_ptr(C++11)
本篇我们只讲auto_ptr指针的实现

auto_ptr指针的实现

temlpate<typename T>
class Auto_Ptr
{
public:
	Auto_Ptr(T* ptr)
		:mptr(ptr)
	{}
	~Auto_Ptr()
	{
		delete mptr;
	}
	T* operator->()
	{
		return mptr;
	}
	T& operator*()
	{
		return *mptr;
	}
private:
	T* mptr;
};
class Test
{
public:
	void Show()
	{
		std::cout << "hello world!" << std::endl;
	}
};
int main()
{
	int* p = new int(10);
	Auto_Ptr<int> pa = new int(10);
	*p = 20;
	*pa = 20;

	Test* ptest = new Test();
	ptest->Show();

	Auto_Ptr<Test> apl = new Test();
	apl->Show();
	return 0;
	
}

auto_ptr存在的问题
对于智能指针的使用我们是这样的

int main()
{
	Auto_ptr<int> ap1 = new int;
	Auto_ptr<int> ap2 = apl;

	int *p = new int;
	int *q = p;
	return 0;
}

对于上述两行代码:

Auto_ptr<int> ap1 = new int;
Auto_ptr<int> ap2 = ap1;

它的设计是这样的:
首先我们生成的是ap1这个对象,ap1这个对象中有一个指针mptr,这个mptr指向了一个堆内存。接下来通过拷贝构造生成了ap2这个对象。ap2中也有一个指针是mptr。同样ap2这个对象也指向了这个堆内存。如下图所示:
在这里插入图片描述

但是当对象的生存周期到了之后,ap2进行销毁,由系统调动析构函数,释放指向的这个堆内存,如下图所示:
在这里插入图片描述
但是由于ap1和ap2指向的是同一个堆内存,所有ap1进行销毁的时候还是会再释放一遍。所带来的问题是同一个堆内存被所次释放,程序崩溃。
那么如何解决这个问题呢?
因为auto_ptr实现的是所有权唯一(一个堆内存只允许一个智能指针去管理它)
那么atuo_ptr是怎么做的呢?
它会回收旧的智能指针的所有权,也就是ap2指向这个堆内存的时候,ap1就会变成旧的智能指针,同时会让ap1指向为空。保证了这个堆内存只有一个指针指向。也就是保证了这个智能指针所有权唯一的特点。如下图所示:

在这里插入图片描述
代码中是这样处理的:主要是在拷贝构造函数中处理。

temlpate<typename T>
class Auto_Ptr
{
public:
 Auto_Ptr(T* ptr)
  :mptr(ptr)
 {}
 Auto_Ptr(Auto_Ptr<T>& rhs)
 {
 	mptr = rhs.Release();//先是旧的智能指针将原来的指向的堆内存保存下来,然后将旧的智能指针置为空,然后将原来保存下来的指针赋值给新的指针。就相当于新的智能指针指向了该堆内存,同时也取消掉了旧智能指针的所有权。
 }
 Auto_Ptr<T>& operator=(Auto_Ptr<T>& rhs)
 {
 	if(this != &rhs)
 	{
 		delete mptr;
 		mptr = rhs.Release();
 	}
 	return *this;
 }
 ~Auto_Ptr()
 {
  delete mptr;
 }
 T* operator->()
 {
  return mptr;
 }
 T& operator*()
 {
  return *mptr;
 }
private:
 T* Release()
 {
 	T* tmp = mptr;//首先将指针指向的堆内存保存下来
 	mptr = NULL;//然后将本身置成空
 	return tmp;//接下来将保存的地址返回出去
 }
 T* mptr;
};

但是atuo_ptr也是有缺点的:
拷贝或者赋值过程中,导致旧智能指针提前失效。
那么如何解决atuo_ptr指针失效的问题呢?
我们继续给出下一个指针

带标志位的智能指针

这个指针不属于C++标准库中的一个指针。
这个指针保证了智能指针的所有权不唯一,释放权唯一

template<typename T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:mptr(ptr),flag(true)
	{}
	SmartPtr(SmartPtr<T>& rhs)
	{
		mptr = rhs.mptr;
		flag - rhs.flag;
		rhs.flag = false;
	}
	SmartPtr<T>& operator=(SmartPtr<T>& rhs)
	{
		if(this != &rhs)
		{
			this->~SmartPtr();
			mptr = rhs.mptr;
			flag = rhs.flag;
			rhs.flag = false;
		}
		return *this;
	}
	~SmartPtr()
	{
		if(flag)
		{
			delete mptr;
		}
		mptr = NULL;     
	}
	T* operator*()
	{
		return mptr;
	}
	T& operator*()
	{
		return *mptr;
	}
private:
	T* mptr;
	int flag;//释放权的标识。true代表flag对这个堆内存有释放权,false代表flag对这个堆内存没有释放权。
};
int main()
{
	SmartPtr<int> sp1 = new int;
	SmartPtr<int> sp2 = sp1;
	return 0;
}

带标志位的智能指针存在的问题:释放权转移也会导致智能指针失效,权限转移。
auto_ptr的几点注意事项:

  • auto_ptr不能共享所有权
  • auto_ptr不能指向数组
  • auto_ptr不能作为容器的成员
  • 不能通过复制操作来初始化auto_ptr
    std::auto_ptr p(new int(42)); //OK
    std::atuo_ptrp = new int(42);//Error
    这是因为auto_ptr的构造函数被定义了explicit
  • 不要把auto_ptr放入容器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值