smart-pointer

Posted _BitterSweet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了smart-pointer相关的知识,希望对你有一定的参考价值。

原理

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

常用的智能指针

(1) shared_ptr

实现原理:采用引用计数器的方法,允许多个智能指针指向同一个对象,每当多一个指针指向该对象时,指向该对象的所有智能指针内部的引用计数加1,每当减少一个智能指针指向对象时,引用计数会减1,当计数为0的时候会自动的释放动态分配的资源。

智能指针将一个计数器与类指向的对象相关联,引用计数器跟踪共有多少个类对象共享同一指针
每次创建类的新对象时,初始化指针并将引用计数置为1
当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数
对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数
调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)
(2) unique_ptr

unique_ptr采用的是独享所有权语义,一个非空的unique_ptr总是拥有它所指向的资源。转移一个unique_ptr将会把所有权全部从源指针转移给目标指针,源指针被置空;所以unique_ptr不支持普通的拷贝和赋值操作,不能用在STL标准容器中;局部变量的返回值除外(因为编译器知道要返回的对象将要被销毁);如果你拷贝一个unique_ptr,那么拷贝结束后,这两个unique_ptr都会指向相同的资源,造成在结束时对同一内存指针多次释放而导致程序崩溃。

(3) weak_ptr

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

(4) auto_ptr

主要是为了解决“有异常抛出时发生内存泄漏”的问题 。因为发生异常而无法正常释放内存。

auto_ptr有拷贝语义,拷贝后源对象变得无效,这可能引发很严重的问题;而unique_ptr则无拷贝语义,但提供了移动语义,这样的错误不再可能发生,因为很明显必须使用std::move()进行转移。

auto_ptr不支持拷贝和赋值操作,不能用在STL标准容器中。STL容器中的元素经常要支持拷贝、赋值操作,在这过程中auto_ptr会传递所有权,所以不能在STL中使用。

shared_ptr

template<class T>
class Shared_ptr
{
public:
	//构造
	Shared_ptr(T* ptr)
		:_ptr(ptr)
		,_countPtr(new int(1))
		,mutex(new mutex)
	{}
	//析构
	~Shared_ptr()
	{
		subRef();
		if (*_CountPtr == 0)
		{
			delete _ptr;
			delete _CountPtr;
			delete _mtx;
		}
	}
	//拷贝构造
	Shared_ptr(const Shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _CountPtr(sp._CountPtr)
		, _mtx(sp._mtx)
	{
		addCount();
	}
	//赋值运算符重载
	Shared_ptr<T> operator = (const Shared_ptr<T>& sp)
	{
		if (_ptr != sp._ptr)
		{
			if (subCount() == 0)
			{
				delete _ptr;
				delete _CountPtr;
				delete _mtx;
			}
			_ptr = _CountPtr;
			_CountPtr = sp._CountPtr;

			addCount();
		}
		return *this;
	}

	//重载 *
	T& operator*()
	{
		return *_ptr;
	}
	//重载 ->
	T& operator ->()
	{
		return _ptr;
	}
	//获取数量
	int GetCount()
	{
		return *_CountPtr;
	}
	int addCount()
	{
		_mtx->lock();
		(*_CountPtr)++;
		_mtx->unlock();
		return *_CountPtr;
	}
	int subCount()
	{
		_mtx->lock();
		(*_CountPtr)--;
		_mtx->unlock();
		return *_CountPtr;
	}
private:
	T *_ptr;
	int* _CountPtr;
	mutex* _mtx;
};

以上是关于smart-pointer的主要内容,如果未能解决你的问题,请参考以下文章

smart-pointer

微信小程序代码片段

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——.vue文件的模板