c++进阶零(智能指针)

一,什么是智能指针

1.智能指针智能指针就是个类,对普通指针进行封装,不管函数三正常结束还是异常结束,他在析构函数中对指针可以进行智能释放
2.普通指针普通指针在使用完成后需要进行手动释放,且容易造成堆的内存泄漏(忘记释放),二次释放,使用智能指针可以避免这些问题

3 在c++11中智能指针分为3种
包含在头文件中,分别为:shared_ptr、unique_ptr、weak_ptr

4,三种智能指针归纳:

类型功能缺点
shared_ptr使用引用次数,当引用次数为0时自动释放 赋 值引用-1 拷贝引用+1 离开作用域自动释放不能循环引用,避免一个原指针被两个shared指针引用
unique_ptr只能指向一个指针对象,离开作用域后自动释放不能拷贝,赋值
weak_ptr作为shared_ptr的辅助智能指针,引用shared_ptr 原指针引用数不变,使用lock获取原指针的资源作为shared_ptr的管理者

二,三种智能指针

2.1,shared_ptr 智能指针

  1. shared_ptr多个指针指向相同的对象,使用引用计数,每一个shared_ptr拷贝都指向相同的内存,每使用他一次,内部的引用>计数器+1,每析构一次-1,减为0时,自动删除所指向的堆内存
  2. 拷贝使得原对象的引用计数增加1,赋值使得原对象引用计数-1,被赋值对象引用+1,当计数为0时,自动释放内存。
    *shared_ptr需要避免循环引用

理解下面一端代码,就可理解shared_ptr:

#include <iostream>
#include <memory>
using namespace std;
int main() {
        weak_ptr<int> wp;
        {
        int a=10;
        shared_ptr<int> ptra=make_shared<int>(a);
        wp=ptra;
        cout<<"未进行任何操作的ptra引用个数"<<ptra.use_count()<<endl;
        //拷贝 因为被拷贝 有两个指针变量在使用 所以+1
        shared_ptr<int> ptra2(ptra);
        cout<<"拷贝后ptra引用个数"<<ptra.use_count()<<endl;
        int b=20;
        int *pb=&a;
        shared_ptr<int> ptrb=make_shared<int>(b);
        cout<<"初始ptrb的引用个数:"<<ptrb.use_count()<<endl;
        //赋值 赋值后取消了对原指针的引用 但是被赋值对象引用+1
        ptra2=ptrb;
        cout<<"ptrb赋值给ptra2后ptra的引用个数:"<<ptra.use_count()<<endl;
        cout<<"当前ptrb的引用个数:"<<ptrb.use_count()<<endl;
        //获取智能指针的原始指针
        pb=ptrb.get();
        cout<<"ptrb的原始指针的值:"<<*pb<<endl;

        }
        //出了作用域 shared_ptr自动清除,引用归0
        cout<<"出了作用域后,ptra的引用个数:"<<wp.use_count()<<endl;
}


在这里插入图片描述2.2 unique_ptr智能指针

  1. unique
    即唯一的,即该智能指针在同一时刻只能指向一个指针对象(通过禁止拷贝,赋值进行实现)但是可以通过move转移所有权,通过release释放所有权
  2. unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)

理解下面一段代码即可理解uniqque_ptr:

#include <iostream>
#include <memory>
using namespace std;
int main()
{


        {
        int a=10;
        //与shared_ptr不同的是可以直接使用原始指针进行拷贝
        unique_ptr<int> uptr(new int(10));
        // std::unique_ptr<int> uptr2 = uptr;  //不能賦值
        //std::unique_ptr<int> uptr2(uptr);  //不能拷貝i
        cout<<"uptr的原始指针的值:"<<*uptr.get()<<endl;
        //转移所有权
        unique_ptr<int> uptr2=move(uptr);

        //cout<<"uptr所有权转换后的值:"<<*uptr.get()<<endl; //转移后不能获取指针的值
        cout<<"uptr2获取所有权后的值:"<<*uptr2.get()<<endl;
        uptr2.release(); //释放所有权
        //cout<<"uptr2获取所有权后的值:"<<*uptr2.get()<<endl; //释放所有权后不能再获取指针的值

        }
        //超过uptr的作用域,内存释放

}

在这里插入图片描述2.3 weak_ptr智能指针
weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,它的构造不会引起指针引用计数的增加,获得资源的观测权

用lock获取原shared_ptr的对象进行操作资源

通过下面代码理解:

#include <iostream>
#include <memory>

int main() {
    {
        std::shared_ptr<int> sh_ptr = std::make_shared<int>(10);

        std::cout <<"当前sh_ptr的引用个数" <<sh_ptr.use_count() << std::endl;

        //weak_ptr引用shared-Ptr
        std::weak_ptr<int> wp(sh_ptr);
        //引用个数不改变
        std::cout <<"weak_ptr引用shared_Ptr后的引用个数:"<<wp.use_count() << std::endl;
        //wp.expired 等价于use_count==0 即判断被观测的资源是否结束
        if(!wp.expired()){
            //用过lock获取shared_ptr的对象进行操作资源
            std::shared_ptr<int> sh_ptr2 = wp.lock(); //get another shared_ptr
            *sh_ptr2 = 100;
            std::cout << "通过wp.lock获取shared对象后的引用个数"<<wp.use_count()<<"操作后的值:"<<*sh_ptr.get() << std::endl;
        }
    }
    //离开作用域自动释放
    //delete memory
}

在这里插入图片描述

循环引用:

例子:一个子类,一个父类,子类引用父类shared指针,父类引用子类shaed指针,当退出域时,二者的引用都不能降为0,导致不能正常删除资源
解决方法:其中一个引用weak指针对象

代码:
循环引用:

#include <iostream>
#include <memory>

class Child;
class Parent;

class Parent {
private:
    std::shared_ptr<Child> ChildPtr;
public:
    void setChild(std::shared_ptr<Child> child) {
        this->ChildPtr = child;
    }

    void doSomething() {
        if (this->ChildPtr.use_count()) {

        }
    }

    ~Parent() {
    }
};

class Child {
private:
    std::shared_ptr<Parent> ParentPtr;
public:
    void setPartent(std::shared_ptr<Parent> parent) {
        this->ParentPtr = parent;
    }
    void doSomething() {
        if (this->ParentPtr.use_count()) {

        }
    }
    ~Child() {
    }
};

int main() {
    std::weak_ptr<Parent> wpp;
    std::weak_ptr<Child> wpc;
    {
        std::shared_ptr<Parent> p(new Parent);
        std::shared_ptr<Child> c(new Child);
        p->setChild(c);
        c->setPartent(p);
        wpp = p;
        wpc = c;
        std::cout << p.use_count() << std::endl; // 2
        std::cout << c.use_count() << std::endl; // 2
    }
    std::cout << wpp.use_count() << std::endl;  // 1
    std::cout << wpc.use_count() << std::endl;  // 1
    return 0;
}

正确引用:

#include <iostream>
#include <memory>

class Child;
class Parent;

class Parent {
private:
//这里改为引用weak
    //std::shared_ptr<Child> ChildPtr;
    std::weak_ptr<Child> ChildPtr;
public:
    void setChild(std::shared_ptr<Child> child) {
        this->ChildPtr = child;
    }

    void doSomething() {
        //new shared_ptr
        if (this->ChildPtr.lock()) {

        }
    }

    ~Parent() {
    }
};

class Child {
private:
    std::shared_ptr<Parent> ParentPtr;
public:
    void setPartent(std::shared_ptr<Parent> parent) {
        this->ParentPtr = parent;
    }
    void doSomething() {
        if (this->ParentPtr.use_count()) {

        }
    }
    ~Child() {
    }
};

int main() {
    std::weak_ptr<Parent> wpp;
    std::weak_ptr<Child> wpc;
    {
        std::shared_ptr<Parent> p(new Parent);
        std::shared_ptr<Child> c(new Child);
        p->setChild(c);
        c->setPartent(p);
        wpp = p;
        wpc = c;
        std::cout << p.use_count() << std::endl; // 2
        std::cout << c.use_count() << std::endl; // 1
    }
    std::cout << wpp.use_count() << std::endl;  // 0
    std::cout << wpc.use_count() << std::endl;  // 0
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值