C++共享指针相互引用性实例(std::shared_ptr,std::weak_ptr)

1 概述

  C++11引入了智能指针std::shared_ptr,不过std::shared_ptr随然好用,但使用不当就可能导致互相引用,导致内存无法释放。本文以实例来演示相互引用,以及解决办法。

2 实例

  本实例定义两个类型Person和Car,Person成员中有Car共享指针变量car_,Car成员中有Person共享指针变量dirver_。
相互引用类图

2.1 代码

#include <iostream>

#include <memory>
#include <string>

class Car;
typedef std::shared_ptr<Car> CarPtr;

class Person
{
    std::string name_;
    CarPtr car_;
public:
    Person(const char* name)
    : name_(name)
    {
        std::cout << "Person()" << std::endl;
    }
    ~Person()
    {
        std::cout << "~Person()" << std::endl;
    }

    std::string name() const { return name_; }
    void setCar(CarPtr const& car);
    void say();
};
typedef std::shared_ptr<Person> PersonPtr;

class Car
{
    PersonPtr dirver_;
    std::string name_;
public:
    Car(const char* name)
    : name_(name)
    {
        std::cout << "Car()" << std::endl;
    }
    ~Car()
    {
        std::cout << "~Car()" << std::endl;
    }

    std::string name() const { return name_; }

    void setDriver(PersonPtr const& persion)
    {
        dirver_ = persion;
    }
    void run()
    {
        if(dirver_)
            std::cout << dirver_->name() << " is driving the " << name()  << "." << std::endl;
        else
            std::cout << "now has not a driver!" << std::endl;
    }
};

void Person::setCar(CarPtr const& car) { car_ = car; }
void Person::say() 
{
    if(car_)
        std::cout << "I have a " << car_->name() << "!" << std::endl;
    else
        std::cout << "I have not any car!";
}

int main(int argc, char *argv[])
{
    auto car = std::make_shared<Car>("Jeep");
    auto dirver = std::make_shared<Person>("James");
    car->setDriver(dirver);
    dirver->setCar(car);
    dirver->say();
    car->run();
    return 0;
}

运行结果:

Car()
Person()
I have a Jeep!
James is driving the Jeep.

从运行结果看Car和Persion的析构函数都没有调用,导致内存泄露。

2.2 原因分析,

修改代码如下:

int main(int argc, char *argv[])
{
    auto car = std::make_shared<Car>("Jeep");
    auto dirver = std::make_shared<Person>("James");
    car->setDriver(dirver);
    dirver->setCar(car);
    dirver->say();
    car->run();
    std::cout << "car's use count: " << car.use_count() << std::endl;
    std::cout << "person's use count: " << dirver.use_count() << std::endl;
    return 0;
}

运行结果

Car()
Person()
I have a Jeep!
James is driving the Jeep.
car's use count: 2
person's use count: 2

从运行结果看:

  • 对象car和dirver的引用计数都是2.
  • 程序运行结束后car和dirver的析构函数后car和dirver引用计数减1变为1。
  • 最终由于引用计数是1而不是0导致,car和driver管理的指针没有释放,相应Car和Person析构函数也就没有调用。

3 解决

对于该问题,C++11引入std::weak_ptr来解决该问题。std::weak_ptr管理std::shared_ptr,不会更加共享指针的引用计数,使用时通过lock接口返回共享指针来使用。
Car代码修改如下:
解决相互引用性

class Car
{
    std::weak_ptr<Person> dirver_;
    std::string name_;
public:
    Car(const char* name)
    : name_(name)
    {
        std::cout << "Car()" << std::endl;
    }
    ~Car()
    {
        std::cout << "~Car()" << std::endl;
    }

    std::string name() const { return name_; }

    void setDriver(PersonPtr const& persion)
    {
        dirver_ = persion;
    }
    void run()
    {
        PersonPtr dirver = dirver_.lock();
        if(dirver)
            std::cout << dirver->name() << " is driving the " << name()  << "." << std::endl;
        else
            std::cout << "now has not a driver!" << std::endl;
    }
};

修改说明:

  • 成员变量dirver_类型定义为std::weak_ptr
  • run函数调用dirver_的lock函数返回共享指针使用。
    运行结果:
Car()
Person()
I have a Jeep!
James is driving the Jeep.
~Person()
~Car()

从运行结果看:

  • Person和Car的析构函数都调用了
  • 问题解决。
  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值