智能指针介绍及对应使用场景

目录

前言

智能指针介绍

使用场景

1.unique_ptr

基础使用

工厂模式

2.shared_ptr

基础使用

单例模式

循环引用情况

3.weak_ptr

基础使用

结语


前言

        开发过程中,遇到了很多使用裸指针的情况,不经意间就容易出现内存泄漏的情况,由此想到了智能指针,借着这个机会,想说如何使用智能指针替换掉一些原始指针的情况(主要还是后续开发都使用智能指针,开闭原则)。

智能指针介绍

智能指针个人觉得就是用面向对象的方式,管理裸指针,离开智能指针对象的作用域也就结束指针生命周期。需要注意的是

  • unique_ptr:独占型,无法使用unique_ptr进行相应的拷贝以及赋值,可以使用std::move(),将对象转移到另外的智能指针对象。
  • share_ptr:共享型,可以使用share_ptr进行拷贝以及赋值,使用引用计数的方式管理指针,多线程安全,但是会出现循环引用的问题。
  • weak_ptr:不参与自动内存管理,观察对应的share_ptr,解决循环引用问题,无法直接使用。使用lock()获取share_ptr,离开作用域,对应的share_ptr计数减少。

使用场景

1.unique_ptr

个人的理解unique_ptr是用于处理一种独特的指针对象,比如说商场出售了很多的饮料(此时是共享的),但是当我付款之后,我买的这瓶饮料就是我独占的了,此时,这瓶饮料就可以作为我这个对象的独占成员对象。此时的独占对象我就觉得可以是unique_ptr。这瓶饮料的成分是独特的,且是我自己的,不归其他人所有。

  • 基础使用

代码内容:

创建unique_ptr<T>对象、C++14 make_unique、操作权转移、创建unique_ptr<T[]>数组对象、C++17 make_unique创建数组对象。

    unique_ptr<int> up1(new int(10));       //存储在栈上
//    unique_ptr<int> up4 = make_unique<int>(10); //C++ 14才允许有make_unique,但不支持动态数组。存储在堆上,但会自动释放
    cout << *up1 << endl;
    *up1 = 15;
    cout << *up1 << endl;

    unique_ptr<int> up2(up1.release());     //释放资源,转移操作权
//    unique_ptr<int> up2(new int(15));     //如果提前初始化,std::move会先释放原来的指针,move之前会调用析构函数,可以试着把int改成析构函数输出的语句,会调用析构函数
//    unique_ptr<int> up2 = std::move(up1);  //移动语义,转移操作权
    
    cout << *up2 << endl;
    if(up1 == nullptr)
    {
        cout << "up1 is nullptr" << endl;
    }
    else
    {
        cout << "up1 is pointer" << endl;
    }
    unique_ptr<int[]> up3(new int[10]);
    up3[0] = 7;
    cout << up3[0] << endl;
//    unique_ptr<int[]> up5 = make_unique<int[]>(5); //C++ 17,动态创建5个对象的数组

 运行结果:

  • 工厂模式

  代码内容:定义饮料接口类、水类、茶类以及超市工厂、使用基类指针调用虚函数完成多态功能。

class Drink
{
public:
    virtual ~Drink(){}
    virtual void info() = 0;
};

class Water : public Drink
{
public:
    virtual void info() override
    {
        cout << "water" << endl;
    }
    virtual void ~Water(){}
};

class Tea : public Drink
{
public:
    virtual void info() override
    {
        cout << "tea" << endl;
    }
    virtual void ~Tea(){}
};

class shop
{
public:
    static unique_ptr<Drink> creatWater()  //返回基类指针
    {
        return unique_ptr<Drink>(new Water);
    }

    static unique_ptr<Drink> creatTea()    //返回基类指针
    {
        return unique_ptr<Drink> (new Tea);
    }
};

int main()
{
    unique_ptr<Drink> dk1 = shop::creatWater();
    unique_ptr<Drink> dk2 = shop::creatTea();
    dk1->info();
    dk2->info();
    return 0;
}

2.shared_ptr

个人的理解share_ptr是一种共享的指针对象,比如说三兄弟共享同一个母亲以及同一个父亲,享受父母的保护。但是母亲、父亲共享三兄弟,此时父母组合了三兄弟的指针,三兄弟共享父母,此时三兄弟组合了父母的指针,引起了循环引用,当所有对象离开作用域时无法正常删除。

  • 基础使用

代码内容:shared_ptr的初始化、赋值、拷贝、reset()、use_count()

    shared_ptr<int> sp1(new int(7));
    shared_ptr<int> sp2 = sp1;
    shared_ptr<int> sp3(sp1);
    cout << *sp2 << endl;
    cout << *sp3 << endl;
    sp1.reset();    //智能指针的引用计数减1,如果为0则释放资源
    if(!sp1)
    {
        cout << "nullptr" << endl;
    }
    *sp2 = 6;
    cout << *sp3 << endl;   //sp2 sp3 依旧共享对象
    cout << sp3.use_count() << endl;  //获取当前shared_ptr的引用计数,不包括weak_ptr

运行结果:

  • 单例模式
class Drink
{
public:
    virtual ~Drink(){}
    virtual void info() = 0;
    static shared_ptr<Drink> instance();
};

class Water : public Drink
{
public:
    virtual ~Water(){}
protected:
    virtual void info() {cout << "water" << endl;}
};

shared_ptr<Drink> Drink::instance()
{
    static shared_ptr<Drink> entity(new Water());
    return entity;
}

int main()
{
    shared_ptr<Drink> entity = Drink::instance();    //获取基类对象指针
    entity->info();
    return 0;
}
  • 循环引用情况

代码内容:人类基类、父亲类、母亲类、儿子类、初始化父亲母亲以及三个儿子类、各个对象行为、释放调用析构函数。(循环引用修改human对象weak_ptr为shared_ptr即可)

class human
{
public:
    virtual ~human(){}
    virtual void behavior() = 0;
    virtual void init(const string& name) {mName = name;}
    virtual string name(){return mName;}
    virtual void setFamily(shared_ptr<human> hm) {mFamily.push_back(hm);}
protected:
    string mName;
    vector<weak_ptr<human>> mFamily;  //循环引用将该weak_ptr替换成share_ptr,将无法正常析构
};

class father : public human
{
public:
    virtual ~father(){cout << mName.c_str() << "~father" << endl;}
    virtual void behavior() override
    {
        cout << "I need to protected my family!" << endl;
    }
};

class mother : public human
{
public:
    virtual ~mother(){cout << mName.c_str() << "~mother" << endl;}
    virtual void behavior() override
    {
        cout << "cook and take care of my family!" << endl;
    }
};

class child : public human
{
public:
    virtual ~child(){cout << mName.c_str() << " ~child " << endl;}
    virtual void behavior() override
    {
        cout << "play game!" << endl;
    }
};

int main()
{
    shared_ptr<human> fa(new father);
    shared_ptr<human> mo(new mother);
    shared_ptr<human> bro1(new child);
    shared_ptr<human> bro2(new child);
    shared_ptr<human> bro3(new child);

    fa->init("fa");
    mo->init("mo");
    bro1->init("bro1");
    bro2->init("bro2");
    bro3->init("bro3");

    fa->setFamily(bro1);
    fa->setFamily(bro2);
    fa->setFamily(bro3);

    mo->setFamily(bro1);
    mo->setFamily(bro2);
    mo->setFamily(bro3);

    bro1->setFamily(fa);
    bro1->setFamily(mo);

    bro2->setFamily(fa);
    bro2->setFamily(mo);

    bro3->setFamily(fa);
    bro3->setFamily(mo);

    fa->behavior();
    mo->behavior();
    bro1->behavior();
    bro2->behavior();
    bro3->behavior();
    return 0;
}

运行结果:

3.weak_ptr

  • 基础使用

weak_ptr是share_ptr的配套使用,是为了避免循环引用出现的。

代码内容:生成weak_ptr对象、weak_ptr的访问方式

    shared_ptr<int> sp(new int(7));
    weak_ptr<int> wp(sp);
    {
        cout << sp.use_count() << endl;
        shared_ptr<int> sp1 = wp.lock();
        cout << *sp1 << endl;
        cout << sp.use_count() << endl;
    }
    cout << sp.use_count() << endl;

运行结果:

结语

以上就是本人在工作中对于遇到的一些指针使用场景,需要修改成智能指针及相关功能的一些实际操作。代码内容都是自己实际编写的,关于智能指针的概念则主要通过chatGPT获取。建议大家还是根据需要学习以及实操(正所谓好记性不如烂笔头)。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值