智能指针:RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。RAII源于C++,在Java,C#,D,Ada,Vala和Rust中也有应用。是为了解决资源管理时的异常安全性提出了该用法。实现了普通指针的指向和解引用的功能,并实现在类的对象构造时初始化对象和析构时负责释放资源。
RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。
异常安全性:
1.抛出异常后,资源不泄露
2.抛出异常后,不会使原有数据恶化(例如正常指针变野指针)
3.少些 try catch ,因为⼤量的 try catch 会影响代码逻辑。导致代码丑陋混乱不优雅
auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理,可想象为管理权转移。auto_ptr有着严重的缺陷,建议尽量不使用。
//AutoPtr管理权转移
template <class T>
class AutoPtr
{
public:
AutoPtr( T* ptr)
:_ptr(ptr)
{}
AutoPtr(AutoPtr <T>& p)
{
this->_ptr = p._ptr;
p._ptr = NULL;
}
~AutoPtr()
{
cout << "~AutoPtr()" << endl;
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
AutoPtr<T>& operator=(AutoPtr<T>& p)
{
if (this != &p)
{
delete this->_ptr;
this->_ptr = p._ptr;
p._ptr = NULL;
}
return *this;
}
protected:
T* _ptr;
};
scoped_ptr有着更严格的使用限制——不能拷贝(即只声明,不定义)。这就意味着scoped_ptr指针是不能转换其所有权的。
//ScopedPtr防拷贝,只声明,不定义
template <class T>
class ScopedPtr
{
public:
ScopedPtr(T* ptr)
:_ptr(ptr)
{}
~ScopedPtr()
{
cout << "~ScopedPtr()" << endl;
delete _ptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
//将拷贝构造和operator= 设为保护,防拷贝
protected:
ScopedPtr (ScopedPtr<T>& p);
ScopedPtr& operator=(ScopedPtr<T>& p);
protected:
T* _ptr;
};
shared_ptr通过使用引用计数,它解决了在多个指针间共享对象所有权的问题,同时也满足容器对元素的要求,因而可以安全地放入容器中。缺点:存在循环引用的问题
循环引用举例:
class B;
class A {
public:
shared_ptr<B> p;
};
class B {
public:
shared_ptr<A> p;
};
int main() {
while (true) {
shared_ptr<A> pa(new A());
shared_ptr<B> pb(new B());
pa->p = pb;
pb->p = pa;
}
return 0;
}
在while循环中,先是在栈中构造了两个智能指针,分别管理两块堆内存,记为A, B。然后两个赋值语句,使得在shared_ptr中,A,B的引用计数均为2,所以在析构掉pa与pb时,他们的引用计数都没能到达0,于是发生了循环引用,于是开始内存泄露。
//仿函数
template <class T>
class Delete
{
public:
void operator()(T* ptr)
{
cout << "delete" << endl;
delete ptr;
}
};
template <class T>
class DeleteArray
{
public:
void operator()(T* ptr)
{
cout << "delete[]" << endl;
delete[] ptr;
}
};
template <class T>
class Fclose
{
public:
void operator()(T* ptr)
{
cout << "fclose" << endl;
fclose(ptr);
}
};
template <class T>
class Free
{
public:
void operator()(T* ptr)
{
cout << "free" << endl;
free(ptr);
}
};
//ShareaPtr引入引用计数
template <class T,class Del=Delete<int>>
class SharedPtr
{
public:
SharedPtr(T* ptr)
:_ptr(ptr)
, _Count(new int(1))
{}
~SharedPtr()
{
cout << "~SharedPtr()" << endl;
Clear();
}
SharedPtr(SharedPtr <T,Del>& p)
:_ptr(p._ptr)
, _Count(p._Count)
{
++(*_Count);
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
SharedPtr<T,Del>& operator=(SharedPtr <T,Del>& p)
{
if (this != &p)
{
Clear();
_ptr = p._ptr;
_Count = p._Count;
++(*_Count);
}
return *this;
}
void Clear()
{
if (--(*_Count) == 0)
{
cout << "delete" << endl;
//delete _ptr;
_del(_ptr);
delete _Count;
}
}
protected:
T* _ptr;
int* _Count;
Del _del;
};
循环引用解决:
weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象