zoukankan      html  css  js  c++  java
  • C++的智能指针学习笔记(初)

    C++ primer plus 16.2节介绍了auto_ptr,该模板类在C++11中已弃用,目前已被shared_ptr代替。
    auto_ptr又叫做智能指针,用于管理动态内存分配的用法。

    为什么要有auto_ptr?

    首先看一个例子,

    void remodel(string &str){
      string *ps = new string(str);
      ...
      str = ps;
      return;
    }
    

    此例子有什么缺陷呢?
    函数结束的时候没有释放内存,这导致了内存的泄露,指针ps会被释放,但是其指向的内存并没有被释放。一般来说,解决new导致的内存泄露的方法是在return之前使用delete.
    但凡是涉及到“别忘了”的操作,都不是最佳的操作,因为一定会有开发者忘记,或者在不经意间删除或者注释掉了这些代码。
    就算是没有忘记,也会因为一些别的操作导致内存无法释放,例如以下的代码:

    void remodel(string &str)
    {
      string *ps = new string(str);
      ...
      if(xxx){
        throw exception();
      }
      str = *ps;
      delete ps;
      return;
    }
    

    在delete执行之前,如果执行过程中产生了异常并抛出,则后续的指令都不会执行,这仍将导致内存泄露。

    如何解决

    首先,我们知道,C++创建一个对象有两种方式,new和直接声明。new一个对象将在堆中动态分配内存来创建一个对象,而直接声明将会在栈内存中创建对象。
    (所谓的堆,是指程序内部除了栈和静态存储区之外的"自由空间(free store)",堆内存用于在程序运行时分配对象。)
    前者的生命周期是全局的,后者则受到作用域限制,也就是说对于前者产生的对象,如果不去主动释放它,则该对象所占据的内存会一直存在,如果没有指针可以指向它,则会导致内存泄露。
    而直接声明的对象,在一个类对象过期的时候,析构函数会在一个对象过期的时候自动执行从而将该对象释放。

    不妨这样思考,如果指针能被封装为一个对象,则这个包含指针的对象过期的时候调用其析构函数,将该指针指向的对象delete,不就能够把它指向的内存也释放了吗?
    于是auto_ptr便诞生了,auto_ptr是一个模板类,这样便可以创建指向任何类型的智能指针。

    auto_ptr的设计和使用

    template<class T>class auto_ptr{
      public:
      explicit auto_ptr(T* p = 0) throw();
    };
    

    throw()意味着构造函数不引发异常,因此请求T类型的auto_ptr将获得一个指向T类型的auto_ptr.

    这样便定义好了一个智能指针,其实非常简单,就是在构造的时候将普通的指针放入了auto_ptr模板类中
    使用的时候

    auto_ptr<double> ap(new double);//在构造函数中填入new出来的对象
    *ap = 23.3;//ap对象的地址其实就是new出来的double对象的地址,所以可以用指针取值的方式赋值。
    

    所以,改造文章开头的remodel函数:

    void remodel(string &str){
      auto_ptr<string> ps(new string(str));
      ...
      if(xxx) throw exception();
    
      str=*ps;
      return;
    }
    

    这里,便不再需要使用delete了。

    shared_ptr和unique_ptr

    C++11摒弃了auto_ptr,主要是由于auto_ptr无法进行指针的传递。auto_ptr必须显式地初始化,即auto_ptr<string> ps(new string("sdf")),
    为了多个指针指向一个new出的对象,C++11提出了shared_ptr,
    shared_ptr中增加了引用计数,有N个指向一个同一个内存区域的shared_ptr时,它们共同维护一个引用计数器。
    shared_ptr的大概实现如下:

    template<typename T> class shared_ptr{
      
    private:
      T* _ptr;//指向的对象
      int *_count;//引用计数器
    
    public:
      ...
      shared_ptr():_ptr((T*)0),_count(0){}
      ~shared_ptr(){
        if(_ptr && --*count==0){
          delete _ptr;
          delete _count;
        }
      }
    };
    

    当智能指针的析构函数启用时,只有引用计数为0的时候,才会进行析构。

  • 相关阅读:
    AJAX异步传输——以php文件传输为例
    js控制json生成菜单——自制菜单(一)
    vs2010中关于HTML控件与服务器控件分别和js函数混合使用的问题
    SQL数据库连接到服务器出错——无法连接到XXX
    PHP错误:Namespace declaration statement has to be the very first statement in the script
    【LeetCode】19. Remove Nth Node From End of List
    【LeetCode】14. Longest Common Prefix
    【LeetCode】38. Count and Say
    【LeetCode】242. Valid Anagram
    【LeetCode】387. First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/goto2091/p/13804187.html
Copyright © 2011-2022 走看看