zoukankan      html  css  js  c++  java
  • 智能指针shared_ptr

    在 C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化; delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。

    动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的。有时我们会忘记释放内存,在这种情况下就会产生内存泄漏;有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针。

    为了更容易(同时也更安全)地使用动态内存,新的标准库提供了两种智能指针(smart pointer)类型来管理动态对象。

    智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象

    新标准库提供的这两种智能指针的区别在于管理底层指针的方式:shared_ptr 允许多个指针指向同一个对象;

    unique_ptr 则"独占"所指向的对象。

    标准库还定义了一个名为 weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在 memory 头文件中。

    share_ptr类

    类似 vector,智能指针也是模板。因此,当我们创建一个智能指针时,必须提供额外的信息——指针可以指向的类型。与vector 一样,我们在尖括号内给出类型,之后是所定义的这种智能指针的名字:

    shared_ptr<string> p1;           // shared_ptr可以指向string
    shared_ptr<list<int>> p2;        // shared_ptr可以指向int的list
    

    默认初始化的智能指针中保存着一个空指针(参见 2.3.2 节,第 48页)。在 12.1.3 节中(见第 412 页),我们将介绍初始化智能指针的其他方法。

    智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空∶

    // 如果p1不为空,检查它是否指向一个空的string
    if (p1 && p1 -> empty())
        *p1 = "hi";  // 如果p1指向一个空的string,解引用p1,将一个新值赋予string
    

    表中列出了shared_ptr和unique_ptr支持的操作

    shared_ptr和unique_ptr都支持的操作
    shared_ptr < T > sp 空智能指针,可以指向类型为T的对象
    shared_ptr < T > up
    p 将p用作一个条件判断,若p指向一个对象,则为true
    *p 解引用p,获得它指向的对象
    p -> mem 等价于(*p) .mem
    p.get() 返回p中保存的指针
    swap(p, q) 交换p和q中的指针
    p.swap(q)
    shared_ptr独有的操作
    makeshared < T > (args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
    shared_ptr < T > p(q) p是shared_ptr q 的拷贝;此操作会递增q中的计数器。q中的指针必须能转换为q
    p.unique() 若p.use_count()为1,则返回true,否则false
    p.use_count() 返回与p共享对象的智能指针的数量
    p = q p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放。

    make_share函数

    最安全的分配和使用动态内存的方法是调用一个名为 make_shared 的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的 shared_ptr。与智能指针一样,make_shared 也定义在头文件 memory 中。

    当要用 make shared 时,必须指定想要创建的对象的类型。定义方式与模板类相同,在函数名之后跟一个尖括号,在其中给出类型:

    // 指向一个值位42的int的shared_ptr
    shared_ptr<int> p3 = make_share<int>(42);
    // p4指向一个值位“999999999”的string
    shared_ptr<int> p4 = make_share<string(10, '9');
    // p5指向一个值初始化的int,即为0
    shared_ptr<int> p5 = make_share<int>();
    

    类似顺序容器的emplace成员,make_shared用其参数来构造给定类型的对象。

    例如,调用 make_shared < string > 时传递的参数必须与 string的某个构造函数相匹配,调用 make_shared < int >时传递的参数必须能用来初始化一个 int,依此类推。

    如果我们不传递任何参数,对象就会进行值初始化。

    当然,我们通常用 auto定义一个对象来保存make_shared的结果,这种方式较为简单:

    // p6 指向一个动态分配的空 vector<string>
    auto p6 = make_shared<vector<int>>();
    

    shared_ptr的拷贝和赋值

    当进行拷贝或赋值操作时,每个 shared ptr都会记录有多少个其他 shared ptr指向相同的对象:

    auto p = make_shared<int>(42);   // p指向的对象只有p一个引用者
    auto q(p);                       // p和q指向相同的对象,此对象有两个引用者
    

    我们可以认为每个 shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。

    无论何时我们拷贝一个 shared_ptr,计数器都会递增。

    例如,当用一个 shared_ptr 初始化另一个 shared_ptr,或将它作为参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。

    当我们给 shared_ptr赋予一个新值或是 shared_ptr被销毁(例如一个局部的 shared_ptr离开其作用域)时,计数器就会递减。一旦一个shared_ptr 的计数器变为0,它就会自动释放自己所管理的对象:

    auto r = make_shared<int>(42);  //  r指向的int只有一个引用者
    r = q;// 给r赋值,令它指向另一个地址
    // 递增q指向的对象的引用计数
    // 递减r原来指向的对象的引用计数
    // r原来来指向的对象已没有引用者,会自动释放
    
  • 相关阅读:
    二维数组问题
    如何在Windows环境下寻找并杀死进程
    关于使用YYYY-MM-dd产生BUG的问题
    boolean在Java中占几个字节的问题
    IDEA启动项目时报错:Error running 'Application': Command line is too long. Shorten command line for Application or also for Spring Boot default configuration.
    mvn package失败,不再支持源选项 1.5。请使用 1.6 或更高版本。
    17蓝桥杯竞赛题“购物单”
    17蓝桥杯竞赛题“取数位”
    微信公众平台开发(ASP.NET)
    宋艳杰个人作品集合
  • 原文地址:https://www.cnblogs.com/lihello/p/14420190.html
Copyright © 2011-2022 走看看