温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++中的智能指针shared_ptr和unique_ptr怎么使用

发布时间:2022-08-23 10:21:23 来源:亿速云 阅读:111 作者:iii 栏目:开发技术

这篇文章主要介绍“C++中的智能指针shared_ptr和unique_ptr怎么使用”,在日常操作中,相信很多人在C++中的智能指针shared_ptr和unique_ptr怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++中的智能指针shared_ptr和unique_ptr怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    shared_ptr

    基本用法: 可以通过构造函数, make_shared<T>辅助函数和reset()方法来初始化shared_ptr

    1. 初始化方法

        shared_ptr<int> p1(new int(1));
        shared_ptr<int> p2 = p1;
        shared_ptr<int> p3;
        p3.reset(new int(1));
        shared_ptr<int> p4 = make_shared<int>(int(5));

    优先使用make_shared来构造, 更加高效

    不能用一个原始指针直接赋值智能指针, 以下方式是错误的

    shared_ptr<int> p5=new int(1); //error

    2.获取智能指针的原始指针: 通过get方法

        shared_ptr<int> ptr = make_shared<int>(int(5));
        int *p=ptr.get();

    3.指定删除器:自定义指针销毁方式

    void ptr_deleter(const int*p)
    {
        delete p;
    }
    shared_ptr<int> p(new int, ptr_deleter);

    第二个参数指定删除器(一个可调用对象, 其中参数为该类型的指针, 如上面为int*)

    当shared_ptr引用计数为0时, 调用传入的而不是默认的删除器来释放对象的内存

    当用shared_ptr管理动态数组时, 需要指定删除器, 因为shared_ptr默认删除器不支持数组对象

    如下使用lambda表达式作为删除器

    shared_ptr<int> p(new int[10],[](int*p){delete []p;});

    通过default_delete作为删除器, 同时封装一个make_shared_array函数来支持数组

    template<typename T>
    shared_ptr<T> make_shared_array(int size)
    {
        return shared_ptr<T>(new T[size],default_delete<T[]>());
    }

    (自测)貌似这样也支持数组

    shared_ptr<int[]> ptr(new int[10]);

    使用shared_ptr注意

    (1)不要用一个原始指针初始化多个shared_ptr

        int *ptr = new int;
        shared_ptr<int> p1(ptr);
        shared_ptr<int> p2(ptr);  //错误

    (2)不要在函数实参中创建shared_ptr

    function(shared_ptr<int>(new int),g());

    参数的计算顺序可能没有固定顺序, 若是new int后执行g()抛出异常, 则shared_ptr还没有创建, 则new int内存泄漏了

    (3)不要用this指针构造shared_ptr作为返回值

    class A
    {
    public:
        shared_ptr<A> get_self()
        {
            return shared_ptr<A>(this);
        }
        ~A()
        {
            cout << ("destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> p1(new A);
        shared_ptr<A> p2 = p1->get_self();
        return 0;
    }

    destructor

    destructor

    以上代码p1和p2相当于同一个new A初始化, 会shared_ptr销毁时, 会重复析构

    正确做法:

    让该类继承enable_shared_from_this<>, 同时调用shared_from_this()返回

    class A :public enable_shared_from_this<A>    //继承
    {
    public:
        shared_ptr<A> get_self()
        {
            return shared_from_this();            //调用该函数
        }
        ~A()
        {
            cout << ("destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> p1(new A);
        shared_ptr<A> p2 = p1->get_self();
        return 0;
    }

    destructor

    只要用shared_ptr, 调用的成员函数里都不能使用this构造, 否则都会出错

    class A
    {
    public:
        void test()
        {
            shared_ptr<A>(this); //错误
        }
        ~A()
        {
            cout<<(  "destructor"  )<<endl;
        }
    };
    shared_ptr<A> p(new A);
    p->test()

    另外, 不要在构造函数里使用shared_from_this

    (4)避免循环引用

    以下代码会由于循环引用, 引用计数值都为1, 导致两个指针都不会析构

    class A;
    class B;
    class A
    {
    public:
        shared_ptr<B> b_ptr;
        ~A()
        {
            cout << ("A destructor") << endl;
        }
    };
    class B
    {
    public:
        shared_ptr<A> a_ptr;
        ~B()
        {
            cout << ("B destructor") << endl;
        }
    };
    int main()
    {
        shared_ptr<A> a_p(new A);
        shared_ptr<B> b_p(new B);
        a_p->b_ptr=b_p;
        b_p->a_ptr=a_p;
    }

    //没有输出

    unique_ptr

    unique_ptr不允许复制, 不允许其他的智能指针共享其内部的指针, 但可以转移

        unique_ptr<int> ptr(new int);
       // unique_ptr<int> ptr2=ptr;    error 不可以赋值
        unique_ptr<int> ptr3=move(ptr); //用move进行转移
        assert(ptr!=nullptr); //转移后ptr为nullptr

    自定义make_unique函数且让其支持定长数组

    思路

    不是数组, 返回unique_ptr<T>

    是数组且非定长数组, 返回unique_ptr<T>, 即不应该调用make_unique<T[10]>(10)而是make_unique<T[]>(10)

    最后过滤掉该定长数组(函数声明为delete)

    // !is_array_v确定不是数组, 返回unique_ptr<T>
    template<typename T,typename ...Args>
    enable_if_t<!is_array_v<T>,unique_ptr<T>> make_unique_(Args&&...args)
    {
        return unique_ptr<T>( new T(forward<Args>(args)...));
    }
    //定长数组如T[10],  不应该调用make_unique<T[10]>(10);而是make_unique<T[]>(10);
    // is_array_v确定是数组且!extent_v<T>确定非定长数组, 返回unique_ptr<T>
    template<typename T,typename ...Args>
    enable_if_t<is_array_v<T>&&!extent_v<T>,unique_ptr<T>> make_unique_(size_t size)
    {
        using U=remove_extent_t<T>;
        return unique_ptr<T>( new U[size]);
    }
    //否之过滤掉该定长数组
    template<typename T,typename ...Args>
    enable_if_t<extent_v<T>,void> make_unique_(Args&&...)=delete;
        unique_ptr<int> ptr= make_unique_<int>(10);
        unique_ptr<int[]> ptr1= make_unique_<int[]>(10);

    不过unique_ptr本身也支持数组, shared_ptr自测也支持, 如下

        unique_ptr<A[]> ptr1(new A[10]);
        shared_ptr<A[]> ptr2(new A[10]);

    unique_ptr也支持删除器, 但和shared_ptr有区别, 要指定删除器类型

        shared_ptr<A> p1(new A[10],[](A*p){delete []p;});
       // unique_ptr<A> p2(new A[10],[](A*p){delete []p;}); 错误
        unique_ptr<A,void(*)(A*)> p2(new A[10],[](A*p){delete []p;}); //正确

    如果希望lambda删除器捕获变量, 则需要用function包装

        unique_ptr<A,void(*)(A*)> p1(new A[10],[&](A*p){delete []p;});       //错误
        unique_ptr<A,function<void(A*)>> p2(new A[10],[&](A*p){delete []p;}); //正确

    到此,关于“C++中的智能指针shared_ptr和unique_ptr怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI