C++STL智能指针

介绍

C++程序设计中堆内存是一个非常频繁的操作,堆内存的申请和释放都由程序员自己管理,虽然自己管理内存提高了程序的效率,但整体来说还是比较麻烦的。使用普通指针,忘了释放很容易造成内存泄漏,二次释放、程序异常时造成泄露,使用智能指针能更好的解决这个问题。
实现原理:RAII(资源分配即初始化)
C++封装类,初始化,生命周期结束时,触发析构,自动回收空间
智能指针的四种类型

  1. auto_ptr
  2. share_ptr
  3. unique_ptr
  4. weak_ptr

实现与使用

auto_ptr

C++98标准 其中由设计缺陷,现在已不适用
(缺陷如代码所示)
C++11引如了share_ptr,unique_ptr,weak_ptr

#include<iostream>
#include<string>
#include<memory>

using namespace std;

class AA
{
public:
	AA(const string s)
	{
		str= s;
		cout<<"AA()"<<endl;
	}
	~AA()
	{
		cout<< "~AA()"<<endl;
	}
	void say()
	{
		cout<<str<<endl;
	}
private:
	string str;
};

int main()
{
	//初始化指针指针 auto_ptr
	//初始化方法1
	{
		std::auto_ptr<AA> ap1(new AA("using auto_ptr")); //ap1 就是智能指针
		ap1->say();  //对象生命结束, 指针回收对象是自动的.
	}
	cout<<"------------------"<<endl;
	//初始化方法2 可以通过reset()方法
	{
		std::auto_ptr<AA> ap1;
		ap1.reset( new AA("using auto_ptr"));
		ap1->say(); 
	}
	cout<<"------------------"<<endl;
	//可以赋值
	{
		std::auto_ptr<AA> ap1(new AA("using auto_ptr"));   //有可能 已经被unique_ptr取代了
		std::auto_ptr<AA> ap2;  // unique_ptr
	 	ap2 = ap1;  // ap2获取ap1的对象
		ap1->say(); // ap2获取ap1的对象, ap1里面没对象,再调用就出问题.
	}

	system("pause");
	return 0;
}

share_ptr

share_ptr和auto_ptr最大的区别就是,share_ptr解决了指针间共享对象所有权的问题,也就是auto_ptr中的复制的奇怪问题,所以满足了容器的要求,可以用于容器中。而auto_ptr显然禁止共享对象所有权,不可以用于容器中。
成员函数:

  1. 默认构造函数,函数参数为变量地址
  2. 拷贝构造函数,函数参数为引用
  3. 重载函数operator*
  4. 重载函数operator->
  5. 重载函数operator=,使之可以进行隐形转换操作,
    注:实际C++源码中是没有这个的,构造函数用关键字explicit声明,在定义对象时必须显示调用初始化,不能使用赋值操作符,进行隐式转换。
  6. 空函数判断
  7. 引用次数统计函数
    注:使用share_ptr也要引用#include<memory>,如下使用简答的源码实现:
#ifndef _SHARED_PTR_H
#define _SHARED_PTR_H
/*
  一个模板T* ptr,指向实际的对象
  一个引用次数
  重载operator*和operator->,使得能像指针一样使用share_ptr
  重载copy constructer,使其引用次数加一
  重载operator=,如果原来的shared_ptr已经有对象
*/
 
template<typename T>
class shared_ptr
{
public:
	shared_ptr(T* p) :count(new int(1)), _ptr(p); //默认构造函数,必须自己显式的开辟内存
	shared_ptr(shared_ptr<T>& p) :count(&(++p.count)), _ptr(p._ptr); //拷贝构造函数,属于强制转换,显式
 
	T& operator*(); //
	T* operator->();
	shared_ptr<T> & operator=(shared_ptr<T>& p); //对等号进行重载,保证保存同为shared_ptr的指针能相互转换,等号
												 //左边计数器减1,右边计数器加1。
	~shared_ptr();
	bool empty();  //检查是否指向一个空T
	int GetCount();
private:
	int* count;  //引用计数器
	T* _ptr;   //每创建一个对象,则有一个指针指向一个shared_ptr类型 
};
 
#endif
#include"_shared_ptr.h"
 
template<typename T>
shared_ptr<T>::shared_ptr(T* p = nullptr) :count(new int(1)), _ptr(p) //默认构造函数,必须自己显式的开辟内存
{
	if (_ptr)
	{
		count = new int(1); //如果初始值不为空,则计数器为1
	}
	else
	{
		count = new int(0); //当初始值为空时,则计数器为0;
	}
} 
 
template<typename T>
shared_ptr<T>::shared_ptr(shared_ptr<T>& p) : count(&(++p.count)), _ptr(p._ptr) //拷贝构造函数,属于强制转换,显式
{
	if (this != p)
	{
		this->_ptr  = p._ptr;
		this->count = p.count;
		*(this->count)++;
	}
} 
 
template<typename T>
T& shared_ptr<T>::operator*()
{
	//assert(this->_ptr == nullptr)
	return *(this->_ptr);
}
 
template<typename T>
T* shared_ptr<T>::operator->()
{
	//assert(this->_ptr == nullptr);
	return this->_ptr;
}
 
template<typename T>
shared_ptr<T>& shared_ptr<T>::operator=(shared_ptr<T>& p) //对等号进行重载,保证保存同为shared_ptr的指针能
														  //相互转换,等号左边计数器减1,右边计数器加1。
{
	++*(p.count); //等式右边引用次数加一,左边引用次数减一
	if (this->_ptr && 0 == --*this->count) //当左边引用次数为零
	{
		delete count;
		delete _ptr;
	}
	this->count = p.count;
	this->_ptr = p._ptr;
	return *this;
}
 
template<typename T>
shared_ptr<T>::~shared_ptr() //当诶空时,清除
{
	if (0 == *(this->count))
	{
		delete count;
		delete _ptr;
	}
}
 
template<typename T>
bool shared_ptr<T>::empty() //检查是否指向一个空T,当为空时,记得count也为零
{
	return _ptr == nullptr;
}
 
template<typename T>
int shared_ptr<T>::GetCount()
{
	return *count;
}

unique_ptr

unique_ptr的构造函数与auto_ptr一样,构造函数采用explicit声明,防止复制/拷贝时不必要的类型转换,在定义对象时必须显示调用初始化式,不能使用赋值操作符进行隐式转换。
注:此代码未包含自定义删除器

成员函数:

  1. get函数:获取内部对象的指针,由于已经重载了()方法,因此和直接使用对象是一样的。
  2. release函数:放弃内部对象的所有权,将内部指针置空,此指针需要手动释放。
  3. reset函数:销毁内部对象并接受新的对象的所有权。
  4. 默认构造函数,函数参数为变量地址
  5. 拷贝构造函数,函数参数为引用
  6. 重载函数operator*
  7. 重载函数operator->
  8. 重载函数operator=
#ifndef UNIQUE_PTR_H
#define UNIQUE_PTR_H
 
template<typename T>
class _unique_ptr
{
public:
	_unique_ptr(T* p = nullptr) :_ptr(p);        //默认构造函数
	_unique_ptr(_unique_ptr<T>& p) :_ptr(p._ptr); //拷贝构造函数
 
	T& operator*();
	T* operator->();
	_unique_ptr<T>& operator=(_unique_ptr<T>& p); //赋值操作符重载
 
	T* get();
	T* release();
	void reset(T* p);
 
private:
	T * _ptr;
};
 
#endif
#include"unique_ptr.h"
 
template<typename T>
_unique_ptr<T>::_unique_ptr(T* p)
{
	_ptr = p;
}
 
template<typename T>
_unique_ptr<T>::_unique_ptr(_unique_ptr<T>& p)
{
	_ptr = p.release();
}
 
template<typename T>
T& _unique_ptr<T>::operator*()
{
	return *(this->_ptr);
}
 
template<typename T>
T* _unique_ptr<T>::operator->()
{
	return this->_ptr;
}
 
template<typename T>
_unique_ptr<T>& _unique_ptr<T>::operator=(_unique_ptr<T>& p)
{
	if (p.get() != this->get())
	{
		delete _ptr;
	}
	_ptr = p._ptr;
}
 
template<typename T>
T* _unique_ptr<T>::get()
{
	return this->_ptr;
}
 
template<typename T>
T* _unique_ptr<T>::release()
{
	T* tmp = _ptr;
	delete _ptr;
	return tmp;
}
 
template<typename T>
void _unique_ptr<T>::reset(T* p)
{
	if (p != _ptr)
	{
		delete _ptr;
	}
	_ptr = p;
}

weak_ptr

weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr。 weak_ptr只是提供了对管理对象的一个访问手段。

weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。定义在 memory 文件中(非memory.h), 命名空间为 std.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SS_zico

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值