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

    // 智能指针会自动释放所指向的对象。
    // shared_ptr的应用场景是:程序需要在多个对象间共享数据
    
    /* 先从应用场景入手吧,说矿工A发现了一个金矿。
     * 然后矿工A喊来了矿工B,一起开采,不久后矿工A劳累过度死了。
     * 矿工B继续开采着矿工A发现的金矿。
     * 但是矿工B不久后得了尘肺病。
     * 这时候如果矿工B喊来了矿工C,那矿工C就继续开采这个金矿,
     * 如果矿工B至死都没有喊anyone,那么这个金矿不再被任何人发现。
     *
     * 我们来说说实现
     * 每个矿工new一个对象,金矿new一个对象。
     * 矿工死了就delte掉,金矿不再被发现也delte掉。
     *
     * 但是我们有没有可能让最后一个矿工死时,金矿被自动delte掉?
     * 这样的话我们就不需要额外管理金矿对象了。
     * 有可能啊,你用共享指针啊。
     * 共享指针管理一个对象,管理一个引用计数。
     * 每次对共享指针赋值和拷贝时,引用计数就加1。
     * 当共享指针被销毁时,引用计数就减1。
     * 这样就变成多个矿工间共享金矿数据了。
     *
     * 下面我们来说说引用计数递增的情况
     * 1 用一个shared_ptr初始化另一个shared_ptr,肯定调用拷贝构造函数喽
     * 2 用一个shared_ptr赋值另一个shared_ptr,肯定调用赋值函数喽
     * 3 将shared_ptr作为参数传递给一个函数,这个也会调用拷贝构造函数
     * 4 将shared_ptr作为函数的返回值,这个也会调用拷贝构造函数
     *
     * 下面我们来说说引用计数递减的情况
     * 1 shared_ptr被销毁,参数出栈是被销毁的一种情况
     * 2 给shared_ptr重新赋值
     *
     * 一旦一个shared_ptr的引用计数变为0,它就会自动释放所管理的对象。
     */
    
    #include <iostream>
    #include <memory>
    
    using namespace std;
    
    struct Gold
    {
        ~Gold() {total = -1;}
        int total{20};
    
        Gold &operator--()
        {
            --total;
            return *this;
        }
    
        const Gold operator--(int)
        {
            Gold tmp = *this;
            --(*this);
            return  Gold(tmp);
        }
    };
    
    class Miner
    {
    public:
        Miner() : gold(make_shared<Gold>()) {}
    
        Miner(const Miner &miner)
        {
            gold = miner.gold;
        }
    
        void dig()
        {
            (*gold)--;
        }
    
        Gold *base()
        {
            return gold.get();
        }
    
    private:
        shared_ptr<Gold> gold;
    };
    
    int main(int argc, char *argv[])
    {
        auto miner1 = new Miner;
        auto miner2 = new Miner(*miner1);
    
        // 代码执行到这里
        // @表示地址 usecount是引用计数
        // miner1的gold @0x605f40
        // miner2的gold @0x605f40
        // shared_ptr的usecount是2
        // 可见miner1和miner2的gold指向同一个对象
        // 引用计数正确
    
        auto gold = miner2->base();
    
        // 代码执行到这里
        // gold @0x605f40
    
        miner1->dig();
        cout << gold->total << endl;
        miner2->dig();
        cout << gold->total << endl;
        miner1->dig();
        cout << gold->total << endl;
    
        delete miner1;
    
        // 代码执行到这里
        // miner1的gold (null)
        // miner2的gold @0x605f40
        // shared_ptr的usecount是1
        // 引用计数正确
    
        miner2->dig();
        cout << gold->total << endl;
    
        delete miner2;
    
        // 代码执行到这里
        // miner1的gold (null)
        // miner2的gold @0x605f20
        // miner2管理的对象(@0x605f40) 已被销毁
        // 调用了Gold的析构函数
        // gold->totle值为-1
        // 至于miner2的gold @0x605f20 ??
        // 管它呢,反正已引用不到
    
        cout << gold->total << endl;
    
        int *p2;
        {
            auto p1 = make_shared<int>(5);
            p2 = p1.get();
    
            // 代码执行到这里
            // p1 @0x605f60
            // usecount是1
            // p2 指向@0x605f60
        }
    
        // 代码执行到这里
        // 代码块出栈了,p1被销毁
        // usecount变为0,所以p1管理的对象也被销毁了
        // ***这是为什么不建议用get的原因
        // 虽然可以正确输出p2所指向的对象,但是这是不确定的
        // p2就是所谓的野指针了
        cout << *p2 << endl;
    
        shared_ptr<int> p4;
        {
            auto p3 = make_shared<int>(5);
            p4 = p3;
    
            // 代码执行到这里
            // p3 @0x605f60
            // p4 @0x605f60
            // usecount是2
        }
    
        // 代码执行到这里
        // 代码块出栈了,p3被销毁
        // usecount变为1,p3并未销毁所管理的对象
        // p4所管理的对象可以正确输出
        cout << *p4 << endl;
    
        return 0;
    }
    
  • 相关阅读:
    前端面试题总结(js、html、小程序、React、ES6、Vue、算法、全栈热门视频资源)
    steps 步骤条、时间轴
    碰撞检测经典解决方案
    延迟渲染(Deferred Shading)技术详解
    配备透明触摸屏 看3D全息投影概念手机
    预渲染技术
    APK改之理(APK IDE)修改APK简单的入门教程
    如何获取显卡的GPU占用率和显存占用情况
    图像编辑之对比度调整 亮度对比度的算法公式
    别被你的双眼所欺骗 100张神奇的视觉欺骗图
  • 原文地址:https://www.cnblogs.com/the-capricornus/p/6383466.html
Copyright © 2011-2022 走看看