C++11智能指针的基本原理及使用

介绍

智能指针是一个类,用来存储指向动态分配对象的指针,负责自动释放动态分配的对象,防止堆内存泄漏。动态分配的资源,交给一个类对象去管理,当类对象声明周期结束时,自动调用析构函数释放资源。

分类

auto_ptr

**已弃用,使用unique_ptr!**auto_ptr有复制语义,拷贝后源对象变得无效,这可能引发很严重的问题;而unique_ptr则无拷贝语义,但提供了移动语义,这样的错误不再可能发生,因为很明显必须使用std::move()进行转移。
auto_ptr不能用在STL标准容器中。STL容器中的元素经常要支持拷贝、赋值操作,在这过程中auto_ptr会传递所有权,所以不能在STL中使用。

1、shared_ptr

采用引用计数器的方法允许多个智能指针指向同一个对象,每当多一个指针指向该对象时,指向该对象的所有智能指针内部的引用计数加1,每当减少一个智能指针指向对象时,引用计数会减1,当计数为0的时候会自动的释放动态分配的资源。智能指针将一个计数器与类指向的对象相关联,引用计数器跟踪共有多少个类对象共享同一指针。

  1. 当每次创建类的新对象时,初始化指针并将引用计数置为1
  2. 当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数
  3. 当对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0则删除对象),并增加右操作数所指对象的引用计数
  4. 当智能指针生命期结束调用析构函数时,减少引用计数(如果引用计数减至0则删除基础对象)

2、unique_ptr

作为对auto_ptr 的改进,unique_ptr 对其持有的堆内存具有唯一拥有权,也就是unique_ptr 不可以拷贝或赋值给其他对象,其拥有的堆内存仅自己独占。unique_ptr 对象销毁时会释放其持有的堆内存。转移一个unique_ptr将会把所有权全部从源指针转移给目标指针,源指针被置空;
unique_ptr不支持普通的拷贝和赋值操作,只能使用std::move移动,局部变量的返回值除外(因为编译器知道要返回的对象将要被销毁),同样不能用在STL标准容器中。

3、weak_ptr

弱引用。 引用计数有一个问题就是互相引用形成环(环形引用),这样两个指针指向的内存都无法释放。需要使用weak_ptr打破环形引用。weak_ptr是一个弱引用,它是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是说,它只引用,不计数。如果一块内存被shared_ptr和weak_ptr同时引用,当所有shared_ptr析构了之后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前使用函数expired()检测是否过期。

shared_ptr的代码实现

以下代码可以很清楚的体现shared_ptr的原理,附有详细注释

template<typename T>
class SharedPtr
{
public:
	//构造时指定管理资源,此时引用计数产生初始值为1 指针形式管理计数
	SharedPtr(T* ptr = NULL):_ptr(ptr), _pcount(new int(1))
	{
	}

	//拷贝构造资源不变,引用计数解引用后累加
	SharedPtr(const SharedPtr& s):_ptr(s._ptr), _pcount(s._pcount)
	{
		(*_pcount)++;
	}

    //拷贝构造传入资源,引用计数解引用后赋值
	SharedPtr<T>& operator=(const SharedPtr& s)
	{
		if (this != &s)
		{
			//本身计数首先减1,为0则释放
			if (--(*(this->_pcount)) == 0)
			{
				delete this->_ptr;
				delete this->_pcount;
			}
			
			//原来管理的资源信息已经释放 赋值为其它资源的参数
			_ptr = s._ptr;
			_pcount = s._pcount;
			*(_pcount)++;
		}
		return *this;
	}
	
	~SharedPtr()
	{
		//先引用计数减1,为0则释放
		--(*(this->_pcount));
		if (*(this->_pcount) == 0)
		{
			delete _ptr;
			_ptr = NULL;
			delete _pcount;
			_pcount = NULL;
		}
	}
	
	//重写运算符
	T& operator*()
	{
		return *(this->_ptr);
	}
	
	T* operator->()
	{
		return this->_ptr;
	}
		
private:
	T* _ptr;	  //管理的资源指针	
	int* _pcount; //指向引用计数的指针 注意是指针
};

你可能感兴趣的:(实际开发,c++,开发语言)