智能指针的简单实现及两种误用方式

最近在自己写智能指针的时候,遇到了一些小的疑惑,也纠正了之前的一些理解上的偏差。

首先是最简单的智能指针的一个实现:

template<class T>
class SmartPointer{
private:
	T* ptr;
public:
	SmartPointer(T* p) :ptr(p){}    //构造函数
	T& operator*(){                  //重载*操作符
		return *ptr;   
	}
	T* operator->(){                 //重载->操作符
		return ptr;
	}
	~SmartPointer(){                 //析构函数
		delete ptr;
	}
};
这与auto_ptr类似,可以完成自动释放内存的功能,但一旦程序员使用了如下的方式:

class A{};
SmartPointer<A> ptr(new A);
SmartPointer<A> ptr1=ptr;
会导致程序崩溃,因为ptr和ptr1两个智能指针会重复delete源指针,所以stl里有了shared_ptr。

下面看一下加入了引用计数的智能指针的实现:

template<class T>
class SharedPointer{
public:
	explicit SharedPointer(T* p) :ptr(p),count(NULL){                            //构造函数,不允许隐式转换
		count = new size_t(1);
	}
	SharedPointer(const SharedPointer& orig):ptr(orig.ptr),count(orig.count){    //复制构造函数
		++*count;
	}
	SharedPointer& operator=(const SharedPointer& rhs){                          //赋值构造函数
		++*(rhs.count);
		if (--*count == 0){                                                  //防止自我赋值时误删
			delete ptr;
		}
		ptr = rhs.ptr;
		count = rhs.count;
		return *this;
	}
	~SharedPointer(){                                                            //析构函数
		if (--*count == 0)
			delete ptr;
	}
	T& operator*(){                                                             
		return *ptr;
	}
	T* operator->(){
		return ptr;
	}
	T* getOriPtr(){
		return ptr;
	}
private:
	T *ptr;
	size_t* count;
};

在SharedPointer里添加了一个指向计数的指针count,每当智能指针被复制构造或者赋值构造的时候,count指向的值都会自增,当count指向的值为0时,智能指针的析构函数才会调用delete释放原始指针的内存。

这里发现了两种可能导致误用的例子,是我在实际实用中发生的。

1.让智能指针指向栈区:

class A{};
A a;
SharedPointer<A> ptr(&a);
这样的使用,编译器将不会报错,但是由于a是存储在栈区的对象,在进程结束前将自动调用析构函数,而我们的智能指针ptr会对栈区使用delete,导致程序崩溃。

2.用同一个源指针构造两个不同的智能指针:

class A{};
A* p=new A;
SharedPointer<A> ptr(p);
SharedPointer<A> ptr1(p);
这样的使用,将导致指针p被两次调用delete;原因是count指向的内存是在构造函数中分配的,ptr和ptr1都是通过构造函数构造出来的,其count分别指向两个不同地址,其值都为1,在ptr析构时,ptr的count指向的值变为0,发生delete p;接下来在ptr1析构时,ptr1的count指向的值变为0,再发生delete p;这样就导致了程序崩溃。

所以在使用智能指针时,应该统一采用如下使用方式:

class A{};
SharedPointer<A> ptr(new A);
SharedPointer<A> ptr1(new A);
这样就可以保证不会出现如上两种错误。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值