何时我们需要智能指针?
- 资源所有权的共享
共享所有权是指两个或多个对象需要同时使用第三个对象的情况。这第三个对象应该如何(或者说何时)被释放?为了确保释放的时机是正确的,每个使用这个共享资源的对象必须互相知道对方,才能准确掌握资源的释放时间。从设计或维护的观点来看,这种耦合是不可行的。更好的方法是让这些资源所有者将资源的生存期管理责任委派给一个智能指针。当没有共享者存在时,智能指针就可以安全地释放这个资源了。
- 要编写异常安全的代码时
异常安全简单地说就是在异常抛出时没有资源泄漏并保证程序状态的一致性。如果一个对象是动态分配的,当异常抛出时它不会自动被删除。由于栈展开以及指针离开作用域,资源可以会泄漏直至程序结束(即使是程序结束时的资源回收也不是由语言所保证的)。不仅可能程序会由于内存泄漏而耗尽资源,程序的状态也可能变得混乱。智能指针可以自动地为你释放这些资源,即使是在异常发生的情况下。
- 避免常见的错误,如资源泄漏
避免常见的错误。忘记调用 delete 是书本中最古老的错误(至少在这本书中)。一个智能指针不关心程序中的控制路径;它只关心在它所指向的对象的生存期结束时删除它。使用智能指针,你不再需要知道何时删除对象。并且,智能指针隐藏了释放资源的细节,因此使用者不需要知道是否要调用 delete, 有些特殊的清除函数并不总是删除资源的。
下面我们来介绍一下智能指针auto_ptr
以下为简化后的auto_ptr的源码:
#include<iostream>
#include<string>
using namespace std;
template<class _Ty> class auto_ptr
{
public:
typedef auto_ptr<_Ty> _Myt;//自身类型
typedef _Ty element_type;//所指对象类型
explicit auto_ptr(_Ty *_Ptr = 0): _Myptr(_Ptr)//显式的构造函数 默认构造一个空指针
{
}
auto_ptr(_Myt& _Right): _Myptr(_Right.release())//复制构造函数
{
}
_Myt& operator=(_Myt& _Right)//重载赋值运算符
{
reset(_Right.release());
return (*this);
}
~auto_ptr()//析构函数
{
delete _Myptr;
}
template<class _Other> operator auto_ptr<_Other>()//将对象的地址转换为auto_ptr类型
{
return (auto_ptr<_Other>(*this));
}
_Ty& operator*() const//重载*运算符 获得所指对象内容
{
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
return (*get());
}
_Ty *operator->() const // 重载->运算符 获得所指对象地址
{
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
return (get());
}
_Ty *get() const //返回自身的值,即所指对象的地址
{
return (_Myptr);
}
_Ty *release() //返回当前对象的地址, 并将指针置空, 即放弃所占资源
{
_Ty *_Tmp = _Myptr;
_Myptr = 0;
return (_Tmp);
}
void reset(_Ty *_Ptr = 0)//释放所指对象, 将指针指向另一个对象
{
if (_Ptr != _Myptr)
delete _Myptr;
_Myptr = _Ptr;
}
private:
_Ty *_Myptr; // 指向对象的指针
};
int main()
{
auto_ptr<string> p (new string("xiaohuai"));
return 0;
}
auto_ptr是怎样实现资源所有权的转让呢?
我们从源码中的复制构造函数可以看出,它调用了函数release()
**从函数release的源码中我们可以看出,它先将原来的指针保存起来进temp,然后将原指针置空,最后将temp返回
这样我们在复制构造函数中用temp初始化了另一个对象,这样的操作就是将原有的资源所有权转让给了另一个对象,赋值同理**