C++智能指针的使用:shared

编程入门 行业动态 更新时间:2024-10-12 22:31:26

C++智能<a href=https://www.elefans.com/category/jswz/34/1768268.html style=指针的使用:shared"/>

C++智能指针的使用:shared

系列文章目录

本章内容:
(1)shared_ptr、weak_ptr、unique_ptr的介绍
(2)单独使用share_ptr造成的内存泄漏
(3)shared_ptr和weak_ptr的配合使用


文章目录

  • 系列文章目录
  • 前言
  • 一、shared_ptr、weak_ptr、unique_ptr的使用
    • 1.1 shared_ptr
    • 1.2 weak_ptr
      • 1、weak_ptr指针的创建
      • 2、weak_ptr模板类提供的成员方法
    • 1.3 unique_ptr
  • 二、使用步骤
    • 1.shared_ptr单独使用案例
    • 2.weak_ptr和shared_ptr配合使用案例
  • 总结


前言

C/C++ 为了实现对内存的细粒度的操作,没有设计垃圾收集器。因此,使用 C/C++ 编写项目时,开发人员需要格外注意内存的申请和释放。本文介绍了shared_ptr和weak_ptr源码,分析了它们对内存泄漏的检测方式,并指出它们所存在的不足。希望读者可以通过改
进指针算法或 share_ptr 来规避内存泄漏,尽量不要写出连
检测算法也无法处理的代码结构。


提示:以下是本篇文章正文内容,下面案例可供参考

一、shared_ptr、weak_ptr、unique_ptr的使用

1.1 shared_ptr

share_ptr是C++11新添加的智能指针,它限定的资源可以被多个指针共享。

只有指向动态分配的对象的指针才能交给 shared_ptr 对象托管。将指向普通局部变量、全局变量的指针交给 shared_ptr 托管,编译时不会有问题,但程序运行时会出错,因为不能析构一个并没有指向动态分配的内存空间的指针。

1.2 weak_ptr

C++11 weak_ptr智能指针
和 shared_ptr、unique_ptr 类型指针一样,weak_ptr 智能指针也是以模板类的方式实现的。weak_ptr( T 为指针所指数据的类型)定义在头文件,并位于 std 命名空间中。因此,要想使用 weak_ptr 类型指针,程序中应首先包含如下 2 条语句:

#include <memory>
using namespace std;

第 2 句并不是必须的,可以不添加,则后续在使用 unique_ptr 指针时,必须标注std::。

需要注意的是,C++11标准虽然将 weak_ptr 定位为智能指针的一种,但该类型指针通常不单独使用(没有实际用处),只能和 shared_ptr 类型指针搭配使用。甚至于,我们可以将 weak_ptr 类型指针视为 shared_ptr 指针的一种辅助工具,借助 weak_ptr 类型指针, 我们可以获取 shared_ptr 指针的一些状态信息,比如有多少指向相同的 shared_ptr 指针、shared_ptr 指针指向的堆内存是否已经被释放等等。

需要注意的是,当 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1。也就是说,weak_ptr 类型指针并不会影响所指堆内存空间的引用计数。

除此之外,weak_ptr 模板类中没有重载 * 和 -> 运算符,这也就意味着,weak_ptr 类型指针只能访问所指的堆内存,而无法修改它。

1、weak_ptr指针的创建

创建一个 weak_ptr 指针,有以下 3 种方式:

  1. 可以创建一个空 weak_ptr 指针,例如:
std::weak_ptr<int> wp1;
  1. 凭借已有的 weak_ptr 指针,可以创建一个新的 weak_ptr 指针,例如:
std::weak_ptr<int> wp2 (wp1);

若 wp1 为空指针,则 wp2 也为空指针;反之,如果 wp1 指向某一 shared_ptr 指针拥有的堆内存,则 wp2 也指向该块存储空间(可以访问,但无所有权)。

  1. weak_ptr 指针更常用于指向某一 shared_ptr 指针拥有的堆内存,因为在构建 weak_ptr 指针对象时,可以利用已有的 shared_ptr 指针为其初始化。例如:
std::shared_ptr<int> sp (new int);
std::weak_ptr<int> wp3 (sp);

由此,wp3 指针和 sp 指针有相同的指针。再次强调,weak_ptr 类型指针不会导致堆内存空间的引用计数增加或减少。

2、weak_ptr模板类提供的成员方法

和 shared_ptr、unique_ptr 相比,weak_ptr 模板类提供的成员方法不多

weak_ptr指针可调用的成员方法

operator=()重载 = 赋值运算符,是的 weak_ptr 指针可以直接被 weak_ptr 或者 shared_ptr 类型指针赋值。
swap(x)其中 x 表示一个同类型的 weak_ptr 类型指针,该函数可以互换 2 个同类型 weak_ptr 指针的内容。
reset()将当前 weak_ptr 指针置为空指针。
use_count()看指向和当前 weak_ptr 指针相同的 shared_ptr 指针的数量。
expired()判断当前 weak_ptr 指针为否过期(指针为空,或者指向的堆内存已经被释放)
lock()如果当前 weak_ptr 已经过期,则该函数会返回一个空的 shared_ptr 指针;反之,该函数返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针。

再次强调,weak_ptr 模板类没有重载 * 和 -> 运算符,因此 weak_ptr 类型指针只能访问某一 shared_ptr
指针指向的堆内存空间,无法对其进行修改。

#include <iostream>
#include <memory>
using namespace std;
int main()
{std::shared_ptr<int> sp1(new int(10));std::shared_ptr<int> sp2(sp1);std::weak_ptr<int> wp(sp2);//输出和 wp 同指向的 shared_ptr 类型指针的数量cout << wp.use_count() << endl;//释放 sp2sp2.reset();cout << wp.use_count() << endl;//借助 lock() 函数,返回一个和 wp 同指向的 shared_ptr 类型指针,获取其存储的数据cout << *(wp.lock()) << endl;return 0;
}

1.3 unique_ptr

unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权。它取代了C++98中的auto_ptr。

unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。

unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。

#include <iostream>
#include <memory>
using namespace std;struct Task {int mId;Task(int id) :mId(id) {cout << "Task::Constructor" << endl;}~Task() {cout << "Task::Destructor" << endl;}
};int main()
{// 通过原始指针创建 unique_ptr 实例//shared_ptr<Task> taskPtr(new Task(23));//int id = taskPtr->mId;//调用其lock函数来获得shared_ptr示例,进而访问原始对象。//weak_ptr<Task> weak1 = taskPtr;//int id = weak1.lock()->mId;unique_ptr<Task> taskPtr(new Task(23));int id = taskPtr->mId;cout << id << endl;return 0;
}

不管函数正常退出还是异常退出(由于某些异常),也会始终调用taskPtr的析构函数。因此,原始指针将始终被删除并防止内存泄漏。

二、使用步骤

1.shared_ptr单独使用案例

两个shared_ptr指针互相引用导致的资源释放失败的例子:

代码如下(示例):

#include <iostream>
#include <memory>
#include <string>
using namespace std;class B;
class A
{
public:shared_ptr<B> pb_;~A(){cout << "A delete\n";}
};
class B
{
public:shared_ptr<A> pa_;~B(){cout << "B delete\n";}
};void fun() {shared_ptr<B> pb(new B());cout << "pb.use_count " << pb.use_count() << endl;//1shared_ptr<A> pa(new A());cout << "pa.use_count " << pa.use_count() << endl;//1pb->pa_ = pa;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2pa->pb_ = pb;//由于share_ptr是共享资源,所以pb所指向的资源的引用计数也会加1cout << "pb.use_count " << pb.use_count() << endl;//2cout << "pa.use_count " << pa.use_count() << endl;//2
}//程序结束时,没有调用A和B的析构函数int main()
{fun();system("pause");return 0;
}

注意,不能用下面的方式使得两个 shared_ptr 对象托管同一个指针:

A* p = new A(10);shared_ptr <A> sp1(p), sp2(p);

sp1 和 sp2 并不会共享同一个对 p 的托管计数,而是各自将对 p 的托管计数都记为 1(sp2 无法知道 p 已经被 sp1 托管过)。这样,当 sp1 消亡时要析构 p,sp2 消亡时要再次析构 p,这会导致程序崩溃。

2.weak_ptr和shared_ptr配合使用案例

代码如下(示例):

#include <iostream>
#include <memory>
#include <string>
using namespace std;class B;
class A
{
public:weak_ptr<B> pb_weak;~A(){cout << "A delete\n";}
};
class B
{
public:shared_ptr<A> pa_;~B(){cout << "B delete\n";}void print() {cout << "This is B" << endl;}
};void fun() {shared_ptr<B> pb(new B());cout << "pb.use_count " << pb.use_count() << endl;//1shared_ptr<A> pa(new A());cout << "pa.use_count " << pa.use_count() << endl;//1pb->pa_ = pa;cout << "pb.use_count " << pb.use_count() << endl;//1cout << "pa.use_count " << pa.use_count() << endl;//2pa->pb_weak = pb;cout << "pb.use_count " << pb.use_count() << endl;//1:弱引用不会增加所指资源的引用计数use_count()的值cout << "pa.use_count " << pa.use_count() << endl;//2shared_ptr<B> p = pa->pb_weak.lock();p->print();//不能通过weak_ptr直接访问对象的方法,须先转化为shared_ptrcout << "pb.use_count " << pb.use_count() << endl;//2cout << "pa.use_count " << pa.use_count() << endl;//2
}//函数结束时,调用A和B的析构函数//资源B的引用计数一直就只有1,当pb析构时,B的计数减一,变为0,B得到释放,
//B释放的同时也会使A的计数减一,同时pa自己析构时也会使资源A的计数减一,那么A的计数为0,A得到释放。int main()
{fun();system("pause");return 0;
}


总结

  1. weak_ptr是一种用于解决shared_ptr相互引用时产生死锁问题的智能指针。如果有两个shared_ptr相互引用,那么这两个shared_ptr指针的引用计数永远不会下降为0,资源永远不会释放。weak_ptr是对对象的一种弱引用,它不会增加对象的use_count,weak_ptr和shared_ptr可以相互转化,shared_ptr可以直接赋值给weak_ptr,weak_ptr也可以通过调用lock函数来获得shared_ptr。
  2. weak_ptr指针通常不单独使用,只能和 shared_ptr
    类型指针搭配使用。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放。即使有weak_ptr指向对象,对象也还是会被释放。
  3. weak_ptr并没有重载operator->和operator
    *操作符,因此不可直接通过weak_ptr使用对象,典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。

更多推荐

C++智能指针的使用:shared

本文发布于:2023-11-15 12:48:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1599911.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:指针   智能   shared

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!