`
haoningabc
  • 浏览: 1477839 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

weak_ptr解决循环引用问题

    博客分类:
  • c
c++ 
阅读更多
C++11引入的三种智能指针中的最后一个:weak_ptr。在学习weak_ptr之前最好对shared_ptr有所了解。如果你还不知道shared_ptr是何物,可以看看我的另一篇文章【C++11新特性】 C++11智能指针之shared_ptr。

1、为什么需要weak_ptr?
在正式介绍weak_ptr之前,我们先来回忆一下shared_ptr的一些知识。我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对象,并维护了一个共享的引用计数器。对于引用计数法实现的计数,总是避免不了循环引用(或环形引用)的问题,shared_ptr也不例外。

我们先来看看下面这个例子:
#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class ClassB;

class ClassA
{
public:
    ClassA() { cout << "ClassA Constructor..." << endl; }
    ~ClassA() { cout << "ClassA Destructor..." << endl; }
    shared_ptr<ClassB> pb;  // 在A中引用B
};

class ClassB
{
public:
    ClassB() { cout << "ClassB Constructor..." << endl; }
    ~ClassB() { cout << "ClassB Destructor..." << endl; }
    shared_ptr<ClassA> pa;  // 在B中引用A
};

int main() {
    shared_ptr<ClassA> spa = make_shared<ClassA>();
    shared_ptr<ClassB> spb = make_shared<ClassB>();
    spa->pb = spb;
    spb->pa = spa;
    // 函数结束,思考一下:spa和spb会释放资源么?
}


上面代码的输出如下:
ClassA Constructor...
ClassB Constructor...
Program ended with exit code: 0

从上面代码中,ClassA和ClassB间存在着循环引用,从运行结果中我们可以看到:当main函数运行结束后,spa和spb管理的动态资源并没有得到释放,产生了内存泄露。

为了解决类似这样的问题,C++11引入了weak_ptr,来打破这种循环引用。

2、weak_ptr是什么?
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它指向一个由shared_ptr管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。不论是否有weak_ptr指向,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。

3、weak_ptr如何使用
接下来,我们来看看weak_ptr的简单用法。

3.1如何创建weak_ptr实例
当我们创建一个weak_ptr时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享,weak_ptr的创建并不会影响shared_ptr的引用计数值。

示例:
int main() {
    shared_ptr<int> sp(new int(5));
    cout << "创建前sp的引用计数:" << sp.use_count() << endl;    // use_count = 1

    weak_ptr<int> wp(sp);
    cout << "创建后sp的引用计数:" << sp.use_count() << endl;    // use_count = 1
}


3.2如何判断weak_ptr指向对象是否存在
既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接访问对象。那么我们如何判断weak_ptr指向对象是否存在呢?C++中提供了lock函数来实现该功能。如果对象存在,lock()函数返回一个指向共享对象的shared_ptr,否则返回一个空shared_ptr。

示例:
class A
{
public:
    A() : a(3) { cout << "A Constructor..." << endl; }
    ~A() { cout << "A Destructor..." << endl; }

    int a;
};

int main() {
    shared_ptr<A> sp(new A());
    weak_ptr<A> wp(sp);
    //sp.reset();

    if (shared_ptr<A> pa = wp.lock())
    {
        cout << pa->a << endl;
    }
    else
    {
        cout << "wp指向对象为空" << endl;
    }
}


试试把sp.reset()这行的注释去掉看看结果有什么不同。

除此之外,weak_ptr还提供了expired()函数来判断所指对象是否已经被销毁。

示例:
class A
{
public:
    A() : a(3) { cout << "A Constructor..." << endl; }
    ~A() { cout << "A Destructor..." << endl; }

    int a;
};

int main() {
    shared_ptr<A> sp(new A());
    weak_ptr<A> wp(sp);
    sp.reset(); // 此时sp被销毁
    cout << wp.expired() << endl;  // true表示已被销毁,否则为false
}


代码输入如下:

A Constructor...
A Destructor...

3.3如何使用weak_ptr
weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

最后,我们来看看如何使用weak_ptr来改造最前面的代码,打破循环引用问题。
class ClassB;

class ClassA
{
public:
    ClassA() { cout << "ClassA Constructor..." << endl; }
    ~ClassA() { cout << "ClassA Destructor..." << endl; }
    weak_ptr<ClassB> pb;  // 在A中引用B
};

class ClassB
{
public:
    ClassB() { cout << "ClassB Constructor..." << endl; }
    ~ClassB() { cout << "ClassB Destructor..." << endl; }
    weak_ptr<ClassA> pa;  // 在B中引用A
};

int main() {
    shared_ptr<ClassA> spa = make_shared<ClassA>();
    shared_ptr<ClassB> spb = make_shared<ClassB>();
    spa->pb = spb;
    spb->pa = spa;
    // 函数结束,思考一下:spa和spb会释放资源么?
}


输出结果如下:
ClassA Constructor...
ClassB Constructor...
ClassA Destructor...
ClassB Destructor...
Program ended with exit code: 0

从运行结果可以看到spa和spb指向的对象都得到释放!
————————————————
分享到:
评论

相关推荐

    C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)

    `shared_ptr`适合需要多个智能指针共享同一对象的情况,`unique_ptr`适用于独占所有权的资源管理,而`weak_ptr`则解决了循环引用的问题。了解并正确使用这些智能指针,是提升C++编程质量的关键。

    C++11智能指针之weak_ptr详解

    其中,`weak_ptr`是为了解决`shared_ptr`中可能出现的循环引用问题而引入的一种特殊类型的智能指针。本文将深入探讨`weak_ptr`的概念、用途及其使用方法。 1. 为什么需要`weak_ptr`? `shared_ptr`是C++11中引入的...

    weak-ptr 和 shared-ptr 源码

    `weak_ptr`主要用于解决`shared_ptr`可能导致的循环引用问题。例如,两个`shared_ptr`互相引用,如果它们之间没有其他强引用,就会形成一个无法自动释放的对象环。`weak_ptr`可以保持对对象的非拥有性引用,不会增加...

    浅析Boost智能指针:scoped_ptr shared_ptr weak_ptr

    主要用于解决循环引用的问题,当对象被`shared_ptr`引用时,`weak_ptr`可以检测到对象是否仍然存在。 #### 特点: 1. **非拥有性**:`boost::weak_ptr` 不控制对象的生命周期,仅在对象存活时提供观察。 2. **避免...

    test_share_ptr

    5. 弱指针`std::weak_ptr`:与`std::shared_ptr`配合使用的弱指针不增加对象的引用计数,主要用于解决循环引用问题。当弱指针试图访问对象时,需要先检查对象是否仍然有效。 ```cpp std::weak_ptr&lt;int&gt; weak_ptr...

    智能指针shared_ptr的Demo

    这在避免循环引用和处理依赖关系时非常有用。 总之,`shared_ptr`是C++中实现内存管理的重要工具,它提供了安全、方便的内存管理机制,使得开发者能更专注于业务逻辑,而不是内存管理。通过深入理解并熟练使用`...

    shared_ptr

    为了解决这个问题,引入了`weak_ptr`。 ### weak_ptr `weak_ptr`被设计为对`shared_ptr`所指向的对象进行弱引用,它不增加引用计数,因此不会阻止所指向的对象被释放。`weak_ptr`的目的是提供一种访问已经被`...

    Boost智能指针示例源码

    `weak_ptr`通常用于解决`shared_ptr`的循环引用问题。在有循环引用的场景中,如果两个`shared_ptr`相互引用,它们的引用计数将永远不会降为零,导致内存无法释放。`weak_ptr`可以作为观察者,当`shared_ptr`引用计数...

    C++智能指针循环引用问题分析.pdf

    解决循环引用的方法是使用`weak_ptr`。`weak_ptr`不会增加`shared_ptr`的引用计数,因此可以打破循环引用。修改上述代码,将`shared_ptr`替换为`weak_ptr`之一: ```cpp class B; // 前置声明 class A { public: ...

    Boost智能指针

    在C++编程中,合理地使用`shared_ptr`和`weak_ptr`能够有效地帮助开发者管理内存资源,特别是解决循环引用等复杂场景下的内存管理问题。理解这两种智能指针的特性以及如何正确使用它们,对于编写高质量、健壮的C++...

    shared_ptr只能对new的内存操作

    - **可与`std::weak_ptr`配合使用**:`std::weak_ptr`不增加引用计数,用于防止循环引用问题。 #### shared_ptr只能对new的内存操作 如标题所示,“shared_ptr只能对new的内存操作”这一说法强调了`std::shared_...

    84、智能指针的原理、常用的智能指针及实现.pdf

    `weak_ptr`用于解决循环引用问题,当`shared_ptr`的引用计数为0时,即使有`weak_ptr`存在,对象也会被删除。在使用`weak_ptr`前,应先检查它是否有效,防止访问已被删除的对象。 4. `auto_ptr`:`auto_ptr`是C++98...

    c++智能指针

    在实际编程中,程序员需要能够预见和识别可能产生循环引用的场景,并适时使用std::weak_ptr来解决这个问题。需要注意的是,std::weak_ptr是一种编译期的解决方案,并不能自动检测程序运行时产生的循环引用。因此,...

    暗黑风格-C++八股文-v1.0.pdf

    当`shared_ptr`不存在时,`weak_ptr`尝试访问对象会失败,这避免了引用循环和悬挂指针的问题。`weak_ptr`必须先转换为`shared_ptr`才能访问对象。 这些智能指针的设计旨在提高C++程序员的安全性和效率,减少内存...

    05_请说一下你理解的 C++ 中的四个智能指针1

    `weak_ptr`主要用于打破循环引用,当两个`shared_ptr`相互引用时,它们的引用计数永远不会降为零,导致内存无法释放。通过使用`weak_ptr`,可以安全地跟踪一个对象,而不影响其生命周期。 智能指针的使用极大地提升...

    c++11 智能指针(csdn)————程序.pdf

    weak_ptr 是一种弱智能指针,用于解决 shared_ptr 的循环引用问题。weak_ptr 不会增加引用计数,可以被用来观察对象的状态。 在使用智能指针时,需要注意以下几点: * 避免使用原始指针,避免内存泄漏和二次释放。...

    v0.3开发文档1

    `weak_ptr`通常用于打破循环引用,例如在上述描述中的HTTP类与时间节点类的互指问题。`weak_ptr`可以安全地观察`shared_ptr`管理的对象,而不会阻止对象的销毁。`use_count()`方法用于检查引用计数,`expired()`更...

    C++与操作系统等面试题1

    ### C++中的四种智能...`unique_ptr`适用于需要独占所有权的情况,`shared_ptr`适用于需要共享所有权的场合,而`weak_ptr`则用来解决循环引用问题。理解和熟练掌握这些智能指针的使用是每个C++开发者的基本技能之一。

    奇妙的C++——智能指针

    这避免了循环引用的问题,当对象被所有std::shared_ptr释放后,std::weak_ptr尝试访问对象时会抛出异常。 智能指针的工作原理主要基于两个关键概念:资源获取即初始化(RAII, Resource Acquisition Is ...

Global site tag (gtag.js) - Google Analytics