zoukankan      html  css  js  c++  java
  • 论C++的智能指针

    一、简介

      参考这篇博客,并且根据《C++ Primer》中相关知识,我总结了C++关于智能指针方面的内容。

      为了解决内存泄漏的问题,便出现了智能指针。STL提供的智能指针有:auto_ptr,unique_ptr,shared_ptr和weak_ptr。其中auto_ptr是C++98提供的方案,C++11已经将其摒弃,并提供了unique_ptr和shared_ptr。

      所有的智能指针都有一个explicit构造函数,以指针作为参数,比如auto_ptr的类模板原型为:

    templet<class T>
    class auto_ptr {
      explicit auto_ptr(T* p = 0) ; 
      ...
    };
    

      因此不能够自动将指针转换为智能指针,并且显示构造:

    shared_ptr<double> pd; 
    double *p_reg = new double;
    pd = p_reg; // not allowed (implicit conversion)
    pd = shared_ptr<double>(p_reg); // allowed (explicit conversion)
    shared_ptr<double> pshared = p_reg; // not allowed (implicit conversion)
    shared_ptr<double> pshared(p_reg); // allowed (explicit conversion)
    

      且所有的指针都应该避免以下情况:

    string vacation("I wandered lonely as a cloud.");
    
    //pvac过期时,程序将把delete运算符用于非堆内存,这是错误的。
    shared_ptr<string> pvac(&vacation); // No
    

    二、auto_ptr

    • 基本用法
    //用法一:构造
    std::auto_ptr<MyClass> m_example(new MyClass());  
      
    //用法二:重置auto\_ptr并且拥有另一个对象  
    std::auto_ptr<MyClass> m_example(new MyClass());  
    m_example.reset(new MyClass());  
      
    //用法三:指针的赋值操作  
    std::auto_ptr<MyClass> m_example1(new MyClass());  
    std::auto_ptr<MyClass> m_example2(new MyClass());  
    m_example2 = m_example1;  
    
    //用法四:撤销主动权,返回其控制的指针  
    std::auto_ptr<MyClass> m_example1(new MyClass());  
    MyClass* pt = m_example1.release();  
    
    //用法五:返回保存的指针,和四不同,此时auto_ptr还控制着该指针
    std::auto_ptr<MyClass> m_example1(new MyClass());  
    MyClass* pt = m_example1.get(); 
    
    • 注意,在用法三的赋值操作中,C++会把m_example1所指向的内存回收,使m_example1 的值为NULL,所以在C++中,应绝对避免把auto_ptr放到容器中。即应避免下列代码:
    /*
        当用算法对容器操作的时候,你很难避免STL内部对容器中的元素实现赋值传递,这样便会使容器中多个元素被置位NULL,而这不是我们想看到的。
    */
    vector<auto_ptr<MyClass>>m_example;
    

    三、shared_ptr

    • 基本用法
    shared_ptr<T> sp //空智能指针,可以指向类型为T的对象
    sp.get() //返回sp中保存的指针
    swap(p,q)
    p.swap(q) //交换p和q中的指针
    make_shared<T>(args) //返回一个智能指针,指向动态分配的类型为T的对象
    shared_ptr<T>p(q) //递增q中指针的计数器
    p = q //递增q中指针的计数器,递减原来p中指针的计数器
    p.user_count() //返回与p共享对象的智能指针的数量(包括自己)
    p.unique() //若p.user_count()为1,返回true
    
    • 注意

      • 当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象;
      • 函数中return智能指针将让计数加一;
      • 尽量不要通过get()函数得到的原指针给别的shared_ptr构造,如下:
      shared_ptr<int> p(new int(42));
      int *q = p.get();
      { //新程序块
          shared_ptr<int> tmp(q);
      } //被销毁,且其内存也会被销毁
      int foo = *p; //未定义,空悬指针
      
    • 自定义释放操作

    void end_connection(connection *p) { disconnect(*p); }
    
    void f(destination &d) {
        connection c = connection(&d);
        shared_ptr<connection> p(&c, end_connection);
        //当f退出时,自动调用end_connection断开连接
    }
    

    四、unique_ptr

      与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,其对象也被销毁。

    • 基本用法
    unique_ptr<T> up //空智能指针,可以指向类型为T的对象
    unique_ptr<T,D> up //使用类型为D的可调用对象来释放它的指针
    up.get() //返回sp中保存的指针
    swap(p,q)
    p.swap(q) //交换p和q中的指针
    u = nullptr //释放u指向的对象,将u置空
    u.release() //返回原指针,放弃控制器,将u置空
    u.reset() //释放u指向的对象
    u.reset(q) //令u指向q这个对象,原对象被释放
    
    • 自定义释放操作
    void end_connection(connection *p) { disconnect(*p); }
    
    void f(destination &d) {
        connection c = connection(&d);
        unique_ptr<connection,decltype(end_connection)> p(&c, end_connection);
        //当f退出时,自动调用end_connection断开连接
    }
    

    五、weak_ptr

      weak_ptr是一种不控制所指对象生存期的只能指针,它指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个shared_ptr销毁,无论是否有weak_ptr,对象都会被销毁。

    • 基本用法
    weak_ptr<T> w //空智能指针,可以指向类型为T的对象
    weak_ptr<T> w(sp) //绑定一个shared_ptr
    w = p //p可以是shared_ptr或weak_ptr
    w.reset() //将w置空
    w.use_count() //与w共享的shared_ptr数量
    w.expired() //若use_count()为0,返回true
    w.lock() //若expired为true,返回一个shared_ptr,否则返回一个指向w的对象的shared_ptr
    
  • 相关阅读:
    Oracle 备份与恢复 15 个典型问题
    Oracle Rman 增量备份与差异备份
    Oracle top 查询TOP SQL
    Oracle 将另外一张表的列更新到本表的列
    Mysql Innodb 表碎片整理
    python Django 之 Model ORM inspectdb(数据库表反向生成)
    MySQL 5.6比较重要的参数,以及5.5到5.6默认值有过变化的参数
    Python Django 前后端数据交互 之 HttpRequest、HttpResponse、render、redirect
    HTML(一)基础
    Python Django 前后端数据交互 之 HTTP协议下GET与POST的区别
  • 原文地址:https://www.cnblogs.com/vachester/p/7589243.html
Copyright © 2011-2022 走看看