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

如题,我们今天要讲的是 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...
1

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智能指针之weak_ptr详解的文章就介绍到这了,更多相关C++11智能指针 weak_ptr内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++11 智能指针之shared_ptr代码详解

    C++中的智能指针首先出现在"准"标准库boost中. 随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象. 在新标准中,主要提供了shared_ptr.unique_ptr.weak_ptr三种不同类型的智能指针. 接下来的几篇文章,我们就来总结一下这些智能指针的使用. 今天,我们先来看看shared_ptr智能指针. shared_ptr 智能指针 shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许

  • c++11&14-智能指针要点汇总

    学c++的人都知道,在c++里面有一个痛点,就是动态内存的管理,就我所经历的一些问题来看,很多莫名其妙的问题,最后都发现是内存管理不当引起的. 但像java等其他一些语言则不会有这样的问题,为什么呢,因为它们有很好的处理内存的方法,比如java的垃圾回收机制,现在,我们c++终于也有了智能指针. 1. 什么是智能指针 简单地说,智能指针是用对象去管理一个资源指针,同时用一个计数器计算引用当前指针对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器

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

    shared_ptr基本用法 shared_ptr采用引用计数的方式管理所指向的对象.当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1.当shared_ptr离开作用域时,引用计数减1.当引用计数为0时,释放所管理的内存. 这样做的好处在于解放了程序员手动释放内存的压力.之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存:现在这一过程就可以交给shared_ptr去做了. 一般我们使用make_shared来

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

    如题,我们今天要讲的是 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实例可以指向同一个动态对

  • C++ STL 四种智能指针的用法详解

    0.前言 C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:auto_ptr.unique_ptr.shared_ptr 和 weak_ptr,其中 auto_ptr 是 C++98 提出的,C++11 已将其摒弃,并提出了 unique_ptr 替代 auto_ptr.虽然 auto_ptr 已被摒弃,但在实际项目中仍可使用,但建议使用更加安全的 unique_ptr,后文会详细叙述.shared_ptr 和 weak_ptr 则是

  • C++中auto_ptr智能指针的用法详解

    智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足以涵盖auto_ptr的大部分内容. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有

  • C++智能指针之shared_ptr详解

    目录 共享指针的初始化方式 常用成员函数 shared_ptr内存模型 make_shared的优缺点 优点 缺点 引用计数 比较运算符 总结 共享指针的初始化方式 1.裸指针直接初始化,但不能通过隐式转换来构造 2.允许移动构造,也允许拷贝构造 3.通过make_shared构造 例: #include <iostream> #include <memory> class Frame {}; int main() { std::shared_ptr<Frame> f(

  • C++11智能指针中的 unique_ptr实例详解

    在前面一篇文章中,我们了解了 C++11 中引入的智能指针之一 shared_ptr 和 weak_ptr ,今天,我们来介绍一下另一种智能指针 unique_ptr . 往期文章参考: [C++11新特性] C++11 智能指针之shared_ptr [C++11新特性] C++11智能指针之weak_ptr unique_ptr介绍 unique是独特的.唯一的意思,故名思议,unique_ptr可以"独占"地拥有它所指向的对象,它提供一种严格意义上的所有权. 这一点和我们前面介绍

  • C++11 智能指针的具体使用

    目录 智能指针的原理 RAII 智能指针的原理 auto_ptr 1.auto_ptr的使用及问题 unique_ptr shared_ptr shared_ptr的循环引用 智能指针的原理 RAII RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存.文件句柄.网络连接.互斥量等等)的简单技术. 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源. 借此,我

  • 基于C#调用c++Dll结构体数组指针的问题详解

    C#调用c++dll文件是一件很麻烦的事情,首先面临的是数据类型转换的问题,相信经常做c#开发的都和我一样把学校的那点c++底子都忘光了吧(语言特性类). 网上有一大堆得转换对应表,也有一大堆的转换实例,但是都没有强调一个更重要的问题,就是c#数据类型和c++数据类型占内存长度的对应关系. 如果dll文件中只包含一些基础类型,那这个问题可能可以被忽略,但是如果是组合类型(这个叫法也许不妥),如结构体.类类型等,在其中的成员变量的长度的申明正确与否将决定你对dll文件调用的成败. 如有以下代码,其

  • C++11智能指针unique_ptr用法使用场景分析

    一.概述 C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:auto_ptr.unique_ptr.shared_ptr 和 weak_ptr,其中 auto_ptr 是 C++98 提出的,C++11 已将其摒弃,并提出了 unique_ptr 替代 auto_ptr.虽然 auto_ptr 已被摒弃,但在实际项目中仍可使用,但建议使用更加安全的 unique_ptr,后文会详细叙述.shared_ptr 和 weak_ptr 则是

  • C++11新增的包装器详解

    目录 function bind function 目前,我们的知识深度已知的可调用对象类型有: 函数指针 仿函数 / 函数对象 lambda表达式 现在我们有一个函数模板 template<class F, class T> T useF(F f, T x) { static int count = 0; cout << "count:" << &count << endl; return f(x); } 对于函数模板,编译器会

随机推荐