C++基础 智能指针 关于std::shared_ptr循环应用问题

目录

1.首先复习一下智能指针

2.说下std::shared_ptr循环问题


1.首先复习一下智能指针

在C++11中,引入了新的智能指针类,用于更安全和方便地管理动态分配的资源,避免内存泄漏和悬空指针等问题。以下是C++11中的三种主要智能指针:

【1】std::unique_ptr

1,std::unique_ptr 是一种独占式智能指针,用于管理唯一的对象,确保只有一个指针可以访问该对象。不能赋值或拷贝给其他unique_ptr,可以通过移动语义来转移所有权.通过 std::make_unique 函数可以创建 std::unique_ptr 对象(推荐这中方式创建对象),如:std::unique_ptr<int> ptr = std::make_unique<int>(42);

....
{
    std::unique_ptr<int> c1 = std::make_unique<int>(100);
    std::unique_ptr<int> c2 = std::make_unique<int>(200);
    std::unique_ptr<int> c3(c2); //err
    //如果上面错误修改成下面
    std::unique_ptr<int> c3(std::move(c2)); //c2为空
    c2.get() //err
    
}

2,使用 std::unique_ptr 可以自动释放动态分配的内存,当指针超出作用域或被重置时,它会自动删除所管理的对象。

int main()
{
    std::unique_ptr<int> c1 = std::make_unique<int>(20);
    {
        std::unique_ptr<int> c1 = std::make_unique<int>(20);
        //c1.reset();  不影响下面的c1打印
        cout << c1.get() << end;  //超出作用域就会释放
    }
    cout << c1.get() << end;
}

3,需要注意unique_prt作函数参数时,需要注意形参还是实参。

void funtion1(std::unique_ptr<int> c1)
{
    c1.get();
}

void funtion2(std::unique_ptr<int>& c1)
{
    c1.get();
}

....
{
    std::unique_ptr<int> val1 = make_unique<int>(1);
    std::unique_ptr<int> val2 = make_unique<int>(2);
    funtion1(val1);//err
    funtion1(std::move(val1));
    val1.get(); //err
    
    funtion2(val2 );
    
}

4.unique_ptr转shared_ptr(可以unique_ptr作函数返回值,这样shared_ptr也可以用)

....
{
    std::unique_ptr<int> c1 = make_unique<int>(10);
    std::shared_ptr<int> c2 = std::move(c1);
    c1.get(); /err
}

 【2】std: :shared_ptr:

1,std::shared_ptr 是一种共享式智能指针,多个指针可以同时共享对同一对象的拥有权。

2,std::shared_ptr 使用引用计数技术追踪所管理对象的引用数量,当引用计数变为零时,自动销毁所管理的对象。

3,通过 std::make_shared 函数可以创建 std::shared_ptr 对象,如:std::shared_ptr<int> ptr = std::make_shared<int>(42);

【3】std::weak_ptr

1,std::weak_ptr 是一种弱引用智能指针,它可以解决 std::shared_ptr 的循环引用问题。

2,std::weak_ptr 指向 std::shared_ptr 管理的对象,但不会增加引用计数。因此,当所有 std::shared_ptr 对象超出作用域后,即使还有 std::weak_ptr 对象存在,所管理的对象也会被销毁。

3,通过 std::shared_ptr 的 std::weak_ptr 构造函数可以创建 std::weak_ptr 对象,如:std::weak_ptr<int> weakPtr = sharedPtr;

2.说下std::shared_ptr循环问题

#include <iostream>
#include <memory>
using namespace std;


class A;
class B;

class A {
public:
    std::shared_ptr<B> bptr;
    ~A() {
        cout << "A is deleted" << endl; // 析构函数后,才去释放成员变量
    }
};

class B {
public:
    std::shared_ptr<A> aptr;
    ~B() {
        cout << "B is deleted" << endl;  // 析构函数后,才去释放成员变量
    }
};

int main()
{
    std::shared_ptr<A> pa;

    {
        std::shared_ptr<A> ap = std::make_shared<A>();
        std::shared_ptr<B> bp = std::make_shared<B>();
        ap->bptr = bp;
        bp->aptr = ap;
    }
    return 0;
}

上述情况形成了闭环,没有其他指针指向它们时,就会导致循环引用问题。这种情况下,内存无法被垃圾收集器正确释放,从而可能导致内存泄漏,在这种情况下,A的实例可以通过bPtr引用B的实例,反之亦然。但是,如果这些是唯一的引用,那么垃圾收集器无法确定这两个对象何时不再需要,因为它们互相引用,形成了一个循环。

解决办法:

常见的

解决这种问题的一种常见方法是使用std::weak_ptr代替std::shared_ptrstd::weak_ptr不会增加所指向对象的引用计数,因此不会阻止其被垃圾回收。当你有需要访问一个std::weak_ptr所指向的对象时,你可以临时将其升级为std::shared_ptr。如果在此期间没有其他的std::shared_ptrstd::weak_ptr访问过这个对象,那么这个对象就会被垃圾回收。在上述例子中,可以将std::shared_ptr替换为std::weak_ptr 

另一种

另一种可能的解决方案是使用std::atomic<bool>来控制循环引用的对象的生命周期。你可以在对象创建时将该值设置为true,在对象不再需要时将其设置为false。然后,你可以在访问对象之前检查该值是否为true。如果为false,则说明对象已经被销毁,此时访问将导致未定义的行为。因此,这可以防止在对象被销毁后仍被使用的情况。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路奇怪

有钱出钱,没钱多出编程主意啊

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

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

打赏作者

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

抵扣说明:

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

余额充值