在代码中,经常会忘掉释放动态开辟的资源,即使再小心,也会不小心忘记释放,导致内存泄漏。故而引出智能指针。
首先,提出一个概念
RAII(Resource Acquisition Is Initialization):资源分配即初始化,是管理资源、避免内存泄露的方法。方法是:定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的的清理,可以保证资源的正确初始化和释放。
C++库中有有多种智能指针,本文将模拟部分智能指针的实现。
1.AutoPtr-----管理权转移
template<typename T>
class AutoPtr
{
public:
AutoPtr(T* ptr)
:_ptr(ptr)
{
}
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr)
{
ap._ptr = NULL;
}
AutoPtr<T>& operator = (AutoPtr<T>& ap)
{
if (this != &ap)
{
delete _ptr;
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~AutoPtr()
{
if (_ptr)
{
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};
但是这种方法是不可取的,故在C++11中又引出了其他智能指针
2.ScopedPtr------
防拷贝
template<typename T>
class ScopedPtr
{
public:
ScopedPtr(T* ptr)
:_ptr(ptr)
{
}
~ScopedPtr()
{
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
ScopedPtr(const ScopedPtr<T>& sp);
ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
protected:
T* _ptr;
};
该智能指针是只对拷贝构造函数和赋值运算符重载进行声明,不对其进行定义。但是其运用的场景并不是很广泛。
3.SharePtr------引用计数
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr)
:_ptr(ptr)
,_refCount(new int(1))
{
}
SharedPtr(SharedPtr<T>& sp)
:_ptr(sp._ptr)
,_refCount(sp._refCount)
{
++(*_refCount);
}
SharedPtr<T>& operator=(SharedPtr<T>& sp)
{
if (this != &sp)
{
this->Release();
this->_ptr = sp._ptr;
this->_refCount = sp._refCount;
++(*_refCount);
}
return *this;
}
~SharedPtr()
{
Release();
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
void Release()
{
if (--(*_refCount) == 0)
{
delete _ptr;
delete _refCount;
}
}
protected:
T* _ptr;
int* _refCount;
};
该智能指针的优点是:功能强大,使用场景多。缺点是:过于复杂,且会造成循环引用。
弱指针weak_ptr可以解决循环引用。