1、auto_ptr (不要使用的指针)
没有智能指针的c++时代,对堆内存的管理就是简单的new delete。
但是缺点是容易忘了delete释放,即使是资深码农,也可能会在某一个地方忘记delete它,造成内存泄漏。在实际工程中,我们往往更希望把精力放在应用层上,而不是费尽心思在语言的细枝末节(内存的释放)。
于是就有了这个最原始的智能指针。
auto_ptr源码:
template<typename T>
class AutoPtr
{
public:
explicit AutoPtr(T * ptr = NULL):_ptr(ptr), _owner(true)
{}
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr), _owner(true)
{
ap._owner = false;
}
AutoPtr& operator=(AutoPtr<T>& ap)
{
if (this != &ap)
{
delete this->_ptr;
this->_ptr = ap._ptr;
this->_owner = true;
ap._owner = false;
}
return *this;
}
~AutoPtr()
{
if (_owner)
{
this->_owner = false;
delete this->_ptr;
}
}
T& operator*()
{
return *(this->_ptr);
}
T* operator->()
{
return this->_ptr;
}
T* GetStr()
{
return (this->_ptr);
}
protected:
T * _ptr;
bool _owner;
};
auto_ptr 的升级:
template<typename T>
class AutoPtr
{
public: explicit AutoPtr(T* ptr = NULL)
:_ptr(ptr)
{}
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr)
{
ap._ptr = NULL;
}
AutoPtr& operator=(AutoPtr<T>& ap)
{
if (this != &ap)
{
delete this->_ptr;
this->_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~AutoPtr()
{
if (_ptr)
{
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* GetStr()
{
return _ptr;
}
protected:
T* _ptr;
};
2、unique_ptr (一种强引用指针)
它是我的所有物,你们都不能碰它!”——鲁迅
正如它的名字,独占 是它最大的特点。
它其实算是auto_ptr的翻版(都是独占资源的指针,内部实现也基本差不多).
但是unique_ptr的名字能更好的体现它的语义,而且在语法上比auto_ptr更安全(尝试复制unique_ptr时会编译期出错,而auto_ptr能通过编译期从而在运行期埋下出错的隐患)
假如你真的需要转移所有权(独占权),那么你就需要用std::move(std::unique_ptr对象)语法,尽管转移所有权后
还是有可能出现原有指针调用(调用就崩溃)的情况。 但是这个语法能强调你是在转移所有权,让你清晰的知道自己在做什么,从而不乱调用原有指针。
unique_ptr 源码:
template<typename T>
class quiquePtr
{
public:
quiquePtr(T* ptr = NULL)
:_ptr(ptr)
{}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* GetStr()
{
return _ptr;
}
//析构函数
~quiquePtr()
{
if (_ptr != NULL)
{
delete _ptr;
}
}
protected:
//防拷贝
quiquePtr(quiquePtr<T>& ap);
quiquePtr& operator=(quiquePtr<T>& ap);
T* _ptr;
};
3、shared_ptr(一种强引用指针)
“它是我们(shared_ptr)的,也是你们(weak_ptr)的,但实质还是我们的”
——鲁迅
共享对象所有权是件快乐的事情。多个shared_ptr指向同一处资源,当所有shared_ptr都全部释放时,该处资源才释放。(有某个对象的所有权(访问权,生命控制权)
即是 强引用,所以shared_ptr是一种强引用型指针)每个shared_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域(SharedPtrControlBlock)的指针(用原始指针构造时,会new一个SharedPtrControlBlock出来作为计数存放的地方,然后用指针指向它,计数加减都通过SharedPtrControlBlock指针间接操作。)
SharedPtr源码:
template<typename T>
class SharedPtr
{
public:
SharedPtr(T* ptr = NULL):_ptr(ptr), _refCount(new long(1))
{
}
~SharedPtr()
{
_Release();
}
SharedPtr(const SharedPtr<T> & sp):_ptr(sp._ptr), _refCount(sp._refCount)
{
++(*_refCount);
}
//传统写法
SharedPtr<T>& operator=(const SharedPtr<T>& sp)
{
if (this != &sp)
{
this->_Release();
_refCount = sp._refCount;
_ptr = sp._ptr;
++(*_refCount);
}
return *this;
}
//现代写法
/*SharedPtr<T> & operator=(SharedPtr<T> sp)
{
swap(_ptr, sp._ptr);
swap(_refCount, sp._refCount);
++(*_refCount);
return *this;
}*/
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* GetPtr()
{
return _ptr;
}
long GetCount()
{
return *_refCount;
}
protected:
void _Release()
{
if (--(*_refCount) == 0)
{
//delete _ptr;
delete(_ptr);
delete _refCount;
}
}
protected:
T * _ptr;
long * _refCount; //引用计数
template<typename T>
friend class WeakPtr;
};
4、weak_ptr(一种弱引用指针)
它是我们(weak_ptr)的,也是你们(shared_ptr)的,但实质还是你们的”
——鲁迅
weak_ptr是为了辅助shared_ptr的存在,它只提供了对管理对象的一个访问手段,同时也可以实时动态地知道指向的对象是否存活。
(只有某个对象的访问权,而没有它的生命控制权 即是 弱引用,所以weak_ptr是一种弱引用型指针)
内部大概实现:
计数区域(SharedPtrControlBlock)结构体引进新的int变量weak_count,来作为弱引用计数。
每个weak_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域的指针(和shared_ptr一样的成员)。
weak_ptr可以由一个shared_ptr或者另一个weak_ptr构造。
weak_ptr的构造和析构不会引起shared_count的增加或减少,只会引起weak_count的增加或减少。
被管理资源的释放只取决于shared计数,当shared计数为0,才会释放被管理资源, 也就是说weak_ptr不控制资源的生命周期。
但是计数区域的释放却取决于shared计数和weak计数,当两者均为0时,才会释放计数区域。
WeakPtr源码:
template<typename T>
class WeakPtr
{
public:
WeakPtr(T* ptr = NULL) :_ptr(ptr)
{
}
~WeakPtr()
{
}
WeakPtr(const WeakPtr<T>& sp) :_ptr(sp._ptr)
{
}
WeakPtr(const SharedPtr<T>& sp) :_ptr(sp._ptr)
{
}
//传统写法
WeakPtr<T>& operator=(const SharedPtr<T>& sp)
{
_ptr = sp._ptr;
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};