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的时候,才会进行析构。

  • 相关阅读:
    小白安装使用Redis
    Mysql的Sql语句优化
    maximo入门----用户使用提要
    时不时刷刷BOSS 看看技术需求
    2019.7.10整理
    docker使用入门
    docker之windows安装&centOS安装
    HashTable学习
    Hashmap学习
    红黑树学习
  • 原文地址:https://www.cnblogs.com/goto2091/p/13804187.html
Copyright © 2011-2022 走看看