• C++ Primer 笔记——智能指针


    1.新的标准库提供了两种智能指针类型,shared_ptr允许多个指针指向同一个对象,unique_ptr则独占所指的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。

    2.智能指针也是模板,默认初始化的智能指针中保存着一个空指针。

    3.智能指针的操作:

    4.make_shared用参数来构造指定类型的对象。

    std::shared_ptr<int> p = std::make_shared<int>(42);    // 指向一个值为42的int型shared_ptr
    std::shared_ptr<std::string> p1 = std::make_shared<std::string>(2,'1');    // 指向一个值为"11"的string类型shared_ptr
    std::shared_ptr<int> p2 = std::make_shared<int>();    // 值初始化为0

    5.我们可以认为每个shared_ptr有一个引用计数,无论何时我们拷贝一个shared_ptr,计数器都会递增,当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时,计数器就会递减。

    6.当指向一个对象的最后一个shared_ptr被销毁时,shared_ptr类会自动销毁此对象。它是通过析构函数完成销毁工作的。所占用的内存也会被释放。

    7.shared_ptr在无用之后仍然保留的一种可能情况是,你将shared_ptr放在一个容器中(其实已经做了拷贝),随后重排了容器,从而不再需要某些元素,而只使用其中一部分,所以要记得用erase删除不再需要的那些元素。

    8.在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。

    9.默认情况下,动态分配的对象是默认初始化的。这意味着内置类型或组合类型的值将是为定义的,而类类型的对象将用默认构造函数进行初始化。也可以对动态分配的内存进行值初始化,只需在类型名之后跟一对空括号即可。

    int *p = new int;    // 默认初始化,*p的值未定义
    int *p1 = new int();    // 值初始化为0,*p1为0

    10.当我们提供一个括号包围的初始化器,就可以使用auto从此初始化器来推断我们想要分配的对象的类型,但是正因如此,只有当括号中仅有单一初始化器时才可以使用auto。

    int a, b;
    int i = 1;
    auto p = new auto(i);    // p指向一个值为1的int型,但不是指向i
    auto p1 = new auto{a,b};    // 错误,括号中只能有单个初始化器


    11.定位new表达式允许我们向new传递额外的参数。

    int *p = new int;    // 如果分配失败,new抛出std::bad_alloc
    int *p1 = new (std::nothrow) int;    // 如果分配失败,new返回一个空指针


    12.我们传递给idelete的指针必须指向动态分配的内存,或者是一个空指针。释放一块并非new分配的内存,或者将相同的指针值释放多次,其行为是未定义的。

    13.我们可以用new返回的指针来初始化智能指针,接受指针参数的智能指针构造函数是explicit的,因此不能将一个内置指针隐式转换为一个只能指针,必须使用直接初始化形式来初始化一个智能指针。

    std::shared_ptr<int> p = new int(1);     // 错误,必须使用直接初始化形式
    std::shared_ptr<int> p1(new int(1));     // 正确,使用了直接初始化形式


    14.默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象,我们可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,必须提供自己的操作来代替delete。

    15.定义和改变shared_ptr的其他方法:

    16.使用一个内置指针来访问一个智能指针所负责的对象是很危险的,因为我们无法知道对象何时会被销毁。

    void test(std::shared_ptr<int> p)
    {
        // ...
    }
    
    int *p = new int(42);    // p是一个普通指针,不是一个智能指针
    test(p);    // 错误,不能将int*转换为一个shared_ptr<int>
    test(std::shared_ptr<int>(p));    // 合法的,但是一旦函数调用结束,p指向的内存就被释放了
    int j = *p;    // 未定义的,p是一个空悬指针


    17.get用来将指针的访问权限传递给代码,你只有在确定代码不会delete指针的情况下,才能使用get。特别的,永远不要用get初始化另一个智能指针或者为另一个智能指针赋值。

    std::shared_ptr<int> p(new int(1));    // p的引用计数为1
    int *q = p.get();    // 正确,但是注意不要让q被释放
    if (1)
    {
        std::shared_ptr<int> p1(q);
    }    // 程序块结束,p1被销毁,所指的内存被释放
    int i = *p;    //未定义,p所指的内存被释放了

    18.与赋值类似,reset会更新引用计数,如果需要的话,会释放p指向的对象。reset经常与unique一起使用。

    std::shared_ptr<int> p(new int(1));    
    // ...
    if (!p.unique())
        p.reset(new int(2));    // 我们不是唯一用户,分配新的拷贝
    else
        (*p)++;        // 我们是唯一用户,可以直接改变对象的值

    19.如果在new和delete之间发生异常,且异常未被捕获,则内存就永远不会被释放,使用智能指针就可以避免这个问题。

    20.当一个shared_pt(unique_ptr也一样)r被销毁时,默认会对它管理的指针进行delete操作,我们可以自己定义一个删除器函数来代替delete操作。

    class test
    {
    public:
        ~test() {};
    };
    
    void my_delete(test *t)
    {
        t->~test();
    }
    
    std::shared_ptr<test> p(new test(), my_delete);    // p被销毁时会调用my_delete


     

    21.unique_ptr也必须采用直接初始化的形式,而且unique_ptr不支持普通的拷贝或赋值操作,但是有如下操作。

    • 如果release返回的指针没有被其他的指针保存,则不仅内存没有被释放,而且我们丢失了指针

    22.不能拷贝unique_ptr的规则有一个例外,我们可以拷贝或赋值一个将要被销毁的unique_ptr。

    std::unique_ptr<int> clone(int i)
    {
        return std::unique_ptr<int>(new int(i));
    }
    // or
    std::unique_ptr<int> clone1(int i)
    {
        std::unique_ptr<int> ret(new int(i));
        return ret;
    }

    23.weak_ptr是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象。所以weak_ptr不会改变shared_ptr的引用计数。

    24.weak_ptr定义了如下操作:

    25.由于对象可能不存在,我们不能使用weak_ptr直接访问对象,而必须调用lock.

    std::shared_ptr<int> p(new int(1));
    std::weak_ptr<int> p1(p);
    
    if (std::shared_ptr<int> np = p1.lock())    // 如果np为空则不可操作
    {
        (*np)++;
    }
  • 相关阅读:
    angularJS处理table中checkbox的选中状态
    大公司常见表格样式
    github:当你想要使用VSCODE开心提交代码时,出现Git:git@github.com:Permission denied(publickey)解决方案
    angularjs 使用angular-sortable-view实现拖拽效果(包括拖动完成后的方法使用)
    sortable结合angularjs实现拖动排序
    promise的一个简单易懂实例
    angular-ui-select (系列二)远程搜索,页面方框显示的值跟传给后台的值不一样解决方案
    leetcode刷题笔记二十九 两数相除
    scala学习 包和引入
    leetcode刷题笔记二十六 、 二十七、 二十八
  • 原文地址:https://www.cnblogs.com/zoneofmine/p/7287277.html
Copyright © 2020-2023  润新知