目录
一、智能指针概述
二、auto_ptr
三、unique_ptr
五、weak_ptr
六、定制删除器
C++在进行异常处理的时候,若在new和delete之间或在lock和unlock之间就抛出异常了,这样会导致内存泄漏或死锁问题。
为了解决上述问题,于是就引入了智能指针(RAII)的概念。
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。
#include
#include
auto_ptr是C++98提出的智能指针,核心思想是转移管理,但是因其可能引发指针悬空的问题,故很多企业都禁止使用auto_ptr。
#include
using namespace std;
namespace my
{
template
class auto_ptr
{
public:
auto_ptr(T* ptr)
:_ptr(ptr)
{}
auto_ptr(auto_ptr& sp)
:_ptr(sp._ptr)
{
// 管理权转移
sp._ptr = nullptr;
}
auto_ptr& operator=(auto_ptr& ap)
{
// 检测是否为自己给自己赋值
if (this != &ap)
{
// 释放当前对象中资源
if (_ptr)
delete _ptr;
// 转移ap中资源到当前对象中
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~auto_ptr()
{
if (_ptr)
{
cout << "delete:" << _ptr << endl;
delete _ptr;
}
}
// 像指针一样使用
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
}
// 结论:auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr
int main()
{
my::auto_ptr sp1(new int);
my::auto_ptr sp2(sp1); // 管理权转移
// sp1悬空
*sp2 = 10;
cout << *sp2 << endl;
cout << *sp1 << endl; // 对空指针解引用
return 0;
}
unique_ptr的实现原理:单例模式,简单粗暴的防拷贝。
// C++11中开始提供更靠谱的智能指针:unique_ptr / shared_ptr / weak_ptr
#include
#include
namespace my
{
template
class unique_ptr
{
public:
unique_ptr(T* ptr = nullptr)
: _ptr(ptr)
{}
~unique_ptr()
{
if (_ptr)
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
// 进制拷贝,单例模式
unique_ptr(const unique_ptr& sp) = delete;
unique_ptr& operator=(const unique_ptr& sp) = delete;
private:
T* _ptr;
};
}
shared_ptr的实现原理:通过引用计数的方式实现多个shared_ptr对象之间的共享资源。
#include
#include
namespace my
{
template
class shared_ptr
{
public:
shared_ptr(T* ptr = nullptr)
: _ptr(ptr), _pRefCount(new int(1)), _pmtx(new std::mutex)
{}
shared_ptr(const my::shared_ptr& sp)
: _ptr(sp._ptr), _pRefCount(sp._pRefCount), _pmtx(sp._pmtx)
{
AddRef();
}
my::shared_ptr& operator=(const my::shared_ptr& sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_pRefCount = sp._pRefCount;
_pmtx = sp._pmtx;
AddRef();
}
return *this;
}
int use_count()
{
return *_pRefCount;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* get()const
{
return _ptr;
}
~shared_ptr()
{
Release();
}
private:
void AddRef()
{
_pmtx->lock();
*_pRefCount += 1;
_pmtx->unlock();
}
void Release()
{
_pmtx->lock();
bool flag = false;
if (--(*_pRefCount) == 0 && _ptr)
{
delete _ptr;
delete _pRefCount;
flag = true;
}
_pmtx->unlock();
if (flag == true)
delete _pmtx;
}
private:
T* _ptr;
int* _pRefCount;
std::mutex* _pmtx;
};
}
weak_ptr称为弱指针,是一种配合shared_ptr而引入的一种智能指针,为了解决shared_ptr引用成环问题而存在。
weak_ptr指向一个由shared_ptr管理的对象而不影响所指对象的生命周期(不改变所指对象的引用计数)。
weak_ptr不提供 operator* 和 operator-> 的重载,不可直接通过weak_ptr使用对象。
weak_ptr可以指向资源,但不参与资源的管理。
#include
#include
namespace my
{
template
class weak_ptr
{
public:
weak_ptr(T* ptr = nullptr)
: _ptr(ptr)
{}
weak_ptr(const my::shared_ptr& sp)
: _ptr(sp.get())
{}
weak_ptr& operator=(const shared_ptr& sp)
{
_ptr = sp.get();
return *this;
}
private:
T* _ptr;
};
}
#define _CRT_SECURE_NO_WARNINGS 1
// 上述简单实现的 unique_ptr / shared_ptr / weak_ptr 是存在缺陷的
// 一个最大的缺陷就是释放资源只能是默认的 delete 处理
// 所以我们需要定制删除器,可以通过仿函数或者lambda实现
#include
// 定制删除器
template
struct DeleteArray
{
void operator()(const T* ptr)
{
delete[] ptr;
}
};
int main()
{
std::shared_ptr sp1(new int[10], DeleteArray());
std::shared_ptr sp2(new std::string[10], DeleteArray());
std::shared_ptr sp3(fopen("Test.cpp", "w"), [](FILE* ptr) {fclose(ptr); });
}