C++ auto_ptr智能指针

以下内容只要来自《C++标准库》这本书和网上资源:

1.auto_ptr

智能指针能保证,无论在何种情况下,只要自己被摧毁,就一定连带释放其所指资源。auto_ptr是这样的一种指针:它是“它所指向的对象”的拥有者。atuo_ptr要求一个对象只能有一个拥有者,严禁一物二主。不再需要delete,也不再需要catch了。不用担心忘掉delete动作,担心程序异常结束时内存遗失或者资源遗失,只要有智能指针auto_ptr.c++标准库提供的auto_ptr一种帮助程序员防止“被抛出异常时发生资源泄漏”的智能指针。

auto_ptr在头文件#include<memory> 中

  auto_ptr没有所有的指针算术(包括++)运算。auto_ptr不允许你使用一般指针惯用的赋值初始化方式。 例如:

    std::auto_ptr<ClassA> ptr1(new ClassA); //对的

    std::auto_ptr<ClassA> ptr2 =new ClassA;  //错的

2.auto_ptr拥有权的转移

  std::auto_ptr<ClassA> ptr1(new ClassA);//ptr1拥有了那个new出来的对象。

  std::auto_ptr<ClassA> ptr2(ptr1);  //ptr2拥有了那个new出来的对象,ptr1不再拥有它,即拥有权的转移;

                   //这样对象就只会在ptr2被摧毁的时候被delete一次。

  下面的赋值操作和上面的差不多:

  std::auto_ptr<ClassA> ptr1(new ClassA);

  std::auto_ptr<ClassA> ptr2;

  ptr2=ptr1; //拥有权从ptr1转移到ptr2

  2)如果ptr2被赋值之前正拥有另一个对象,赋值时将会delete掉那个对象。

  std::auto_ptr<ClassA> ptr1(new ClassA);

  std::auto_ptr<ClassA> ptr2(new ClassA);

  ptr2=ptr1; //拥有权从ptr1转移到ptr2,ptr2的原来的对象被delete掉。

    拥有权的转移,实质上并非只是被简单拷贝而已。只要发生了拥有权转移,先前的拥有者就失去了拥有权,结果拥有者一旦交出拥有权,就两手空空,只剩下一个null指针在手了。

  只有auto_ptr可以拿来当做另一个auto_ptr的初值,普通指针是不行的。例如:

    std::auto_ptr<ClassA> ptr ;//可以定义空的auto_ptr指针,对于智能指针,因为构造函数有默认值0

    ptr =new ClassA;    //错误,

    ptr =std::auto_ptr<ClassA> (new ClassA);//正确被auto_ptr对象或者auto_ptr指针赋值,

  3)某函数是数据的终点,auto_ptr以传值方式被当作一个参数传递给某函数时。被调用端的参数获得了这个auto_ptr的拥有权,如果函数不再将它传递出去,它所指的对象就会在函数退出时被删除。如:void sink(std::auto_ptr<ClassA> );

  4) 某函数是数据的起点。

    std::auto_ptr<ClassA> f()

    {

      std::auto_ptr<ClassA> ptr(new ClassA);

      //........

      return ptr;

    }

    void g()

    {

      std::auto_ptr<ClassA> p;

      for (int i =0; i <10; i++) {

        p=f();  //p获得f()返回对象的拥有权。每当f()被调用时,它都new一个对象,然后把该对象连同其拥有权一起返回给调用端。

           //一旦循环再次执行这个赋值动作,p原先拥有的对象被删除。当离开g()时,p也被摧毁。

      }

     auto_ptr的语义本身就包含了拥有权,所以如果你无意转交你的拥有权,就不要在参数列表值中使用auto_ptr,也不要以它作为返回值。

   下面的例子本来是想将auto_ptr所指对象的值打印出来,却可能引发了错误:

   //a bad example
#include <iostream>
#include <memory>
using namespace std;

template<class T>
void bad_print(std::auto_ptr<T> p)
{
  if (NULL ==p.get())
    cout <<"NULL";
  else
    cout << *p;
}

int main()
{
  auto_ptr<int> p(new int);
  *p =42;
  bad_print(p); //bad_print调用结束后,p所指向的对象被删除了。
  *p =18;//执行期错误,用g++编译时出现Segmentation fault (core dumped)(段错误)
  return 0;
}

//a bad example
#include <iostream>
#include <memory>
using namespace std;

template<class T>
void bad_print(std::auto_ptr<T> p)
{
  if (NULL ==p.get())
    cout <<"NULL";
  else
    cout << *p;
}

int main()
{
  const auto_ptr<int> p(new int);
  *p =42;
  bad_print(p);  //编译期错误,无法变更constant reference的拥有权
  *p =18;    //ok
  return 0;
}

关键字const并非意味你不能更改auto_ptr所拥有的对象,而是意味着你不能更改auto_ptr的拥有权。例如:

  std::auto_ptr<int> f()

  {

    const std::auto_ptr<int> p(new int);

    std::auto_ptr<int>  q(new int);

    *p =42;//ok,改变值

    bad_print(p);//编译期错误,不能变更拥有权

    *p =*q;  //ok;

    p =q;  //编译期错误

    return p;  //编译期错误

  }

 

  如果使用const auto_ptr作为参数,对新对象的任何赋值操作都将导致编译期错误。就其常数特性而言,const auto_ptr比较类似常数指针(T* const p),

  而非指向常数的指针(const T* p),尽管语法上更像后者。

3.auto_ptr的正确运用:

  1)auto_ptr之间不能共享拥有权

    一个auto_ptr千万不能指向另一个auto_ptr(或其它对象)所拥有的对象,尽管语法上没问题,很多情况下可能也不会发生错误。但是,当一个指针删除该对象后,另一个指针突然间指向一个已被摧毁的对象,那么,如果再使用那个指针进行读写操作,就会引发一场灾难。

  2)并不存在针对array而设计的auto_ptrs

  auto_ptr不能指向array,因为auto_ptr是透过delete而非delete[ ]来释放其所拥有的对象。注意,c++标准程序库并未针对array而设计的auto_ptr。标准程序库另提供了数个容器类别,用来管理数据群。

  3)auto_ptrs绝非一个“四海通用”的智能型指针

   并非任何适用智能指针的地方都适用auto_ptr,特别请注意的是,它不是引用计数型指针——这种指针保证,如果有一组智能型指针指向同一个对象,那么当且仅当最后一个智能型指针被销毁时,该对象才会被销毁。

  4)auto_ptrs不满足STL容器对其他元素的要求

    auto_ptr并不满足STL标准容器对于元素的最基本要求,因为在拷贝和赋值动作之后,原本的auto_ptr和新产生的auto_ptr并不相等。是的,拷贝和赋值之后,原本的auto_ptr会交出拥有权,而不是拷贝给新的auto_ptr。因此绝对不要将auto_ptr作为标准容器的元素。

4. auto_ptr的运用实例:

下面的例子展示autos_ptr转移的拥有权:

#include <iostream>
#include <memory>
using namespace std;

//define output operator for auto_ptr
template <class T>
ostream & operator << (ostream& strm,const auto_ptr<T>& p)
{
  if (p.get() ==NULL) //get()返回auto_ptr指向的那个对象的内存地址
    strm << "NULL";
  else
    strm << *p;
  return strm;
}

int main()
{
  auto_ptr<int> p(new int(42));
  auto_ptr<int> q;
 
  cout << "afer initialization:" <<endl;
  cout << " P: " << p <<endl;
  cout << " q: " << q <<endl;

  q =p;  //改变p的拥有权
  cout << "afer assigning auto pointers::" <<endl;
  cout << " P: " << p <<endl;
  cout << " q: " << q <<endl;
 
  *q +=13;
  p = q;
  cout << "afer change and reassignment:" <<endl;
  cout << " P: " << p <<endl;
  cout << " q: " << q <<endl;

return 0;
}
//输出:

afer initialization:
 P: 42
 q: NULL
afer assigning auto pointers::
 P: NULL
 q: 42
afer change and reassignment:
 P: 55
 q: NULL
//注意:<<操作符的第二个参数是一个const参数,所以并没有发生拥有权的转移。

 

//实例2:展示const auto_ptr的特性:

#include <iostream>
#include <memory>
using namespace std;

template <class T>
ostream & operator << (ostream & strm, const auto_ptr<T>& p)
{
  if (p.get() ==NULL)
    strm <<"NULL" <<endl;
  else
    strm << *p;
  return strm;
}

int main()
{
  const auto_ptr<int> p(new int(42));
  const auto_ptr<int> q(new int(0));
  const auto_ptr<int> r;
  cout << "after initialization:" << endl;
  cout << " p: " << p << endl;
  cout << " q: " << q <<endl;
  cout << " r: " <<r <<endl;

  *q =*p;
  //*r =*p; //ERROR: underfined behavior
  *p =-78;
  cout << "after assigning values:" << endl;
  cout << " p: " << p << endl;
  cout << " q: " << q <<endl;
  cout << " r: " <<r <<endl;

  //p =q; //ERROR at compile time
  //r =p; //ERROR at compile time

  return 0;
}
//输出:

after initialization:
 p: 42
 q: 0
 r: NULL

after assigning values:
 p: -78
 q: 42
 r: NULL
//*r =*p; 这个句子对于一个“未定义对象”的auto_ptr进行提领(dereference)操作

//c++ 标准规定,这会导致未定义错误

 

一般定义的raw指针是这样的使用 class CBase;
class Derive : public CBase {
CBase *pa = new Derive;//如果这里发生异常 比如没有足够的内存分配 pa->调用相关成员函数;//
delete pa;//则不会执行到这里的删除指针内存的操作 发生内存泄漏 }
这样不好,如果有异常 会导致内存泄漏
如果像下面这样写  利用auto_ptr 类指针对象,当对象超过生存期时 会自动调用auto_ptr的析构函数来释放内存,安全比较好 #include "stdafx.h" #include <iostream> #include <algorithm> using namespace std; class CBase {
public:  CBase(){};  ~CBase(){};
 virtual void Print(){}; };
class Derive : public CBase {
public:
 Derive(){};
 Derive(int x):a(x){};  ~Derive(){};  void Print()  {
  cout<<"Hello   "<<a<<endl;  }
protected:
private:  int a; };
void main() {
 auto_ptr<CBase>pa(new Derive(5))   

pa->Print();  getchar();

};

5.auto_ptr的一些常用函数:

  1)auto_ptr::auto_ptr() throw()

    default构造函数、生成一个不拥有任何对象的auto_ptr、将auto_ptr的值初始化为0

  2)explicit auto_ptr::auto_ptr(T* ptr) throw()

    生成一个auto_ptr,并拥有ptr所指对象、*this成为ptr对象的唯一拥有者,不允许有其他拥有者

  3)T* auto_ptr::get() const throw()

    返回auto_ptr所指对象的地址,如果auto_ptr未指向任何对象,返回null指针。

  4)T& auto_ptr::operator * () const throw()

    提领(deferences)操作符,返回auto_ptr所拥有的对象。如果auto_ptr并未拥有任何对象,此调用导致未定义行为(可能导致崩溃).

  5)T* auto_ptr::release() throw()

    放弃auto_ptr原先所拥有的对象的拥有权、返回auto_ptr原先拥有对象(如果有的话)的地址,没有则返回NULL指针

  6)void auto_ptr::reset(T* ptr =0) throw()

    以ptr重新初始化auto_ptr,如果auto_ptr原本拥有对象,先把它删除。

    

 

 

 

C++ auto_ptr智能指针,布布扣,bubuko.com

C++ auto_ptr智能指针

上一篇:【转】使用Beaglebone Black的I2C (二)——使用C语言和i2c-dev驱动


下一篇:JavaScript事件委托的技术原理