auto_ptr用法

1. auto_ptr的意义
auto_ptr是一种智能指针,当系统异常退出的时候避免资源泄漏(内存)。
其他的资源还对应其他的智能指针。

2  auto_ptr的使用
std::auto_ptr<int> test(new int(1));
test将是一个auto_ptr的对象,使用一个int指针进行初始化。
test可以象其他指针一样使用,如使用* 使用->但是++不可以使用,以后也许会扩展,其实难对++做越界管理,也许可以放弃一些速度。

当使用auto_ptr的时候,必须使用显式的类型转化来初始化,如auto_ptr<classA>a(new classA)
而不能使用auto_ptr<classA> a = new classA;

3 auto_ptr所有权的转移
auto_ptr对所有权有严格的约定,一个auto_ptr只能控制一个指针,不能控制多个,当auto_ptr拥有一个指针的时候就不能在拥有其他的指针了。同时,不同的auto_ptr不能拥有同一个指针。但是存在这样的情况,不同的auto_ptr可能控制着相同的对象,不要出现这样的情况。

auto_ptr<int> a(new int); 1
auto_ptr<int> b(a); 2

auto_ptr<int> c = b; 3

auto_ptr<int> d(int); 4

d = c; 5

当2发生的时候,a将所有权放弃,b获得所有权。
当3发生时, b将放弃所有权,c获得所有权
当5发生时, c的所有权给d,d将释放自己的所有权,并把对象删除掉。

4 来源和接收
当auto_ptr以参数的形式传递给函数的时候,作用域同样发生了变化,从之前的作用域变成了函数内部的作用域。过程时这样的,当有auto_ptr作为参数传递到函数内部的时候,首先会交接自己的所有权,所有权交给了函数的参数,作用域编程了函数的内部。函数退出时,函数内部的临时变量都会离开作用域,包括传递进来接收到的auto_ptr,auto_ptr会释放自己保存的资源。在函数退出后,申请的资源就消失了,这种情况可能很出乎人的预料,因为c++一般传递参数都是传值,如何都不会改变变量本身的作用域的。

另一个使用方式,在函数内部返回一个指针,可以避免内存泄漏
#include <iostream>
using namespace std;
template<class T>
auto_ptr<T> getAutoPtr()
{
        auto_ptr<T> rt(new T);
        return rt;
}

int main(void)
{
        auto_ptr<int> rt =getAutoPtr<int>();
        cout<< "["<<*rt<< "]"<< endl;
        return 0;
}


函数的参数可以是auto_ptr<classT>& 类型,当传递auto_ptr的引用的时候,有的时候会传递所有权,有的时候不会,所以永远不要这样做。

当使用const auto_ptr<classT>& 的时候,这个时候如果转移所有权会出错,但是这里存在一个问题,const的意义在于不可以更改传递的参数的数据,但是在这里我们想实现的是不需要传递所有权。这个特性主要应用在模板上,当使用auto_ptr实例话对象的时候也不会出现问题。
所以const auto_ptr<classT>&的意思是不能转移所有权,而不是不能更改数据,这里和c++信息是不一样的,还是少使用好一些。

auto_ptr当作类的成员变量可以避免,当类在构造的时候出现异常,这样如果内存被分配了是不会被释放的,因为如果构造没有完成是不会调用析构函数的,这个时候就没有办法来释放申请的资源了。可以使用
auto_ptr来避免这样的事情发生,如果不想在类种转换所有权,可以使用const来修饰。

5 使用auto_ptr的误区
1 两auto_ptr不要引用同一个对象(t*),这样如果一个auto_ptr释放了资源,另一个或多个就无法获得引用对象的信息。
2 auto_ptr不可以保存array,因为在释放的时候是使用delete,这样就会引起未知的问题。
3 auto_ptr设计成在异常发生的时候,避免内存泄漏,不要乱用。
4 不要在容器中使用auto_ptr,因为无法满足容器的一些要求,比如在copyconstruct和 “=”操作时,会转移所有权。

 ---------------------------------------

 

 

 

 

auto_ptr

 auto_ptr 类是一个模板类,它被定义在 memory 头文件中。

auto_ptr 类可以用于管理由 new 分配的单个对象,但是无法管理动态分配的数组(我们通常不会使用数组,而是使用 vector 代替数组)。auto_ptr 在拷贝和赋值的时候有不寻常的行为,因此auto_ptrs 不能被保存在 stl 的容器中。当 auto_ptr 离开了自己的作用域或者被销毁,由 auto_ptr 管理的对象也会被销毁。

1. 为异常安全的内存分配(Exception-Safe Memory Allocation)使用 auto_ptr

我们看下面的代码:

void Func()

{

  int *pNum = new int(100);

  // code that throws an exceptionthis is not caught inside Func

  delete pNum;

}

我们可以看到,假定在 new 和 delete 之间抛出了一个未捕获的异常,那么内存泄漏发生了,deletepNum 未被执行。这就是非异常安全的内存分配。同样还有一个类似的例子:

void Func()

{

  CMember* pMember = new CMember;

  CTeam* pTeam = QueryTeam(idTeam);

  if (NULL == pTeam)

  return; // Memory leaked

  pTeam->Add(pMember);

}

我们可以看到在动态分配了一个 CMember 对象后,由于出现某种情况函数 return,而 CMember 对象却没有得到释放。

假如我们使用 auto_ptr 类代替,那么内存将会被自动释放:

void Func()

{

  auto_ptr<int> ap(newint(100));

  // …

}

2. 绑定 auto_ptr 到一个指针:

通常的情况,我们这样使用 auto_ptr 类:

auto_ptr<CClass> pObject(new CClass);

这样,我们就完成了 auto_ptr 到指针的绑定。注意,以下这种表达是错误的:

auto_ptr<CClass> pObject = new CClass;

当 auto_ptr 离开自己的作用域时,绑定在 auto_ptr 上的指针指向的对象将被释放。

3. 使用 auto_ptr

auto_ptr 类重载了解引用操作符(*)和箭头操作符(->),这样,我们能够想使用内置指针一样的使用 auto_ptr,例如:

class CClass

{

public:

  void Print();

  // …

}

int main()

{

  std::auto_ptr<CClass>pObj(new CClass);

  pObj->Print(); // the same(*pObj).Print();

}

4. auto_ptr 的赋值和拷贝操作符

内置的指针和 auto_ptr 的区别在于赋值和拷贝,这个需要特别注意。如果是内置指针的拷贝(赋值),那么结果是这两个指针指向同一个对象,而 auto_ptr 则不一样:

auto_ptr<string> ap1(new string("Stegosaurus");

auto_ptr<string> ap2(ap1);

执行完上面的语句后,ap1 将处于非绑定(unbound)状态,并不指向任何对象,被管理的指针的所有权从ap1 转到 ap2,即指针将被 ap2 管理(包括内存的释放等),而不是 ap1。

赋值(拷贝)操作可能导致内存的释放,例如:

std::auto_ptr<std::string> ap1(newstd::string("Pterodactry"));

std::auto_ptr<std::string> ap2;

ap1 = ap2; // 释放内存

正是因为拷贝和赋值会破坏右操作数,所以 auto_ptrs 无法存储在stl 的容器中。stl 的容器需要两个对象在拷贝或者赋值之后相等。

5. auto_ptr 类的函数

1)默认构造函数

auto_ptr<int> pNum; // 没有指向任何对象

*pNum = 100; // 错误

2)get 函数,返回指向对象的指针

if (NULL == pNum.get()) // 指针是否为空

注意,对于处于非绑定状态的 auto_ptr 调用 get 将返回 0。不要做这样的操作:

auto_ptr<int> pNum2(pNum1.get()); // 没有转交所有权

那么 pNum1 管理的指针将被析构两次,这必然带来严重的后果。

3)reset 函数,重设需要管理的指针,首先auto_ptr 会删除当前管理的对象,然后再设置新的对象的指针。另外:

pNum = pNum; // 不会发送任何事情,安全

pNum.reset(pNum->get()); // 不会发送任何事情,安全

4)release 函数释放所有权,返回它管理的指针,不删除指针指向的对象:

auto_ptr<int> pNum2(pNum1.release()); // 等同于下句

auto_ptr<int> pNum2(pNum1); // 等同于上句

6. 编译器的问题

vc6 下的 auto_ptr 并不是标准的,例如:

std::auto_ptr<std::string> ap1(newstd::string("Pterodactry"));

std::auto_ptr<std::string> ap2(ap1);

std::cout << *ap2 << std::endl; // 正常执行

7. 被管理的类的析构函数

如果被管理的类的析构函数为私有的,那么将无法使用 auto_ptr。

 

最后,附上 SGI 的 auto_ptr 源码:

 

template <class _Tp> class auto_ptr {

private:

  _Tp* _M_ptr;

 

public:

  typedef _Tp element_type;

 

  explicit auto_ptr(_Tp* __p = 0)__STL_NOTHROW : _M_ptr(__p) {}

  auto_ptr(auto_ptr& __a)__STL_NOTHROW : _M_ptr(__a.release()) {}

 

#ifdef __STL_MEMBER_TEMPLATES

  template <class _Tp1>auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW

  : _M_ptr(__a.release()) {}

#endif /* __STL_MEMBER_TEMPLATES */

 

  auto_ptr&operator=(auto_ptr& __a) __STL_NOTHROW {

  if (&__a != this) {

  delete _M_ptr;

  _M_ptr = __a.release();

  }

  return *this;

  }

 

#ifdef __STL_MEMBER_TEMPLATES

  template <class _Tp1>

  auto_ptr&operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {

  if (__a.get() != this->get()) {

  delete _M_ptr;

  _M_ptr = __a.release();

  }

  return *this;

  }

#endif /* __STL_MEMBER_TEMPLATES */

 

  // Note: The C++ standard saysthere is supposed to be an empty throw

  // specification here, butomitting it is standard conforming. Its

  // presence can be detected onlyif _Tp::~_Tp() throws, but (17.4.3.6/2)

  // this is prohibited.

  ~auto_ptr() { delete _M_ptr; }

 

  _Tp& operator*() const__STL_NOTHROW {

  return *_M_ptr;

  }

  _Tp* operator->() const__STL_NOTHROW {

  return _M_ptr;

  }

  _Tp* get() const __STL_NOTHROW {

  return _M_ptr;

  }

  _Tp* release() __STL_NOTHROW {

  _Tp* __tmp = _M_ptr;

  _M_ptr = 0;

  return __tmp;

  }

  void reset(_Tp* __p = 0)__STL_NOTHROW {

  if (__p != _M_ptr) {

  delete _M_ptr;

  _M_ptr = __p;

  }

  }

 

  // According to the C++ standard,these conversions are required. Most

  // present-day compilers, however,do not enforce that requirement---and,

  // in fact, most present-daycompilers do not support the language

  // features that these conversionsrely on.

 

#if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \

  defined(__STL_MEMBER_TEMPLATES)

 

public:

  auto_ptr(auto_ptr_ref<_Tp>__ref) __STL_NOTHROW

  : _M_ptr(__ref._M_ptr) {}

 

  auto_ptr&operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {

  if (__ref._M_ptr !=this->get()) {

  delete _M_ptr;

  _M_ptr = __ref._M_ptr;

  }

  return *this;

  }

 

  template <class _Tp1>operator auto_ptr_ref<_Tp1>() __STL_NOTHROW

  { returnauto_ptr_ref<_Tp1>(this->release()); }

  template <class _Tp1>operator auto_ptr<_Tp1>() __STL_NOTHROW

  { returnauto_ptr<_Tp1>(this->release()); }

 

#endif /* auto ptr conversions && member templates */

};

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值