当前位置: 首页 > news >正文

C++ 智能指针的使用

智能指针类型

在C++程序中,普通变量使用栈内存,为函数运行时专用,结束后会自动释放,无须考虑内存释放问题。 但堆内存是共用的,其使用是通过指针变量的new来分配,使用delete来释放,因指针使用方便,很容易让程序员上瘾,其代价是各种原因造成的内存泄露问题,如:

  • 忘记使用delete释放指针变量
  • 指针数组,没有释放成员指针的内存
  • 指针指向一个新地址,原地址内容未释放
  • 异常处理程序,跳过了 delete 语句,致使指针未释放

等等,对服务器应用程序来说,内存泄露常常是致命的。

C++11后,STL增加了智能指针类型,主要有

  • std::shared_ptr,
  • std::weak_ptr
  • std::unique_ptr

智能指针是指针上的包装类,重载了*>等运算符。智能指针类的对象看起来像普通指针。但是,与普通指针不同,在析构函数里释放了指针,因此无须担心忘记释放指针。

unique_ptr用法

unique_ptr是智能指针最简单形式。 unique_ptr指向1个内存对象,而且是指向这个对象的唯一指针,这样可以避免出错。 但尽量不要将unique_ptr做为参数传给第3方接口函数,以避免对方以复制指针的方式来使用它。

在这里插入图片描述

使用语法

#include <memory>
using namespace std;unique_ptr<A>  ptr(new A(初始化参数));
// 或者使用make_unique<T>() 模板函数来初始化unique_ptr
unique_ptr<A> ptr = make_unique<A>(初始化参数); 

如定义1个int 类型的unique_ptr

	int a = 99; unique_ptr<int>  ptr = make_unique<int>(a);// std::unique_ptr x(new int(99)); // *ptr为指向对象的值,ptr.get()为对象地址cout << *ptr << ", " << ptr.get() << endl; 

手工释放

ptr.reset(); 
ptr.reset(new int(1));     //      释放后,重新指向新地址

指向数组

unique_ptr<int[]>  x(new int[5]);    
x[0]=10;
x[1]=11; 

用途:代替普通指针,以避免忘记释放

void NotLeaky() { 
std::unique_ptr x(new int(5)); 
... // lots of code
} 

unique_ptr指向的对象A,只能被1个指针使用

    unique_ptr<A> p1(new A); p1->printA();   //下面语句会报错unique_ptr<A> p2 = p1; p2->printA(); 

允许复制指针,但复制后原指针被释放

   unique_ptr<A> p2 = move(p1); p2->printA();   //  p2已将p1复制p1->printA();   // 报错,p1 已被释放。

定义1个指向类对象的unique_ptr

class Character {
public:string Name;Character(string name = "Frodo") : Name(name){cout << "Greeting: " << Name << endl; }~Character() {cout << "Deleting " << Name << endl; }void printName() { cout << "Name: " << Name << endl; }
};int main() {
unique_ptr<Character> GandalPtr = make_unique<Character>("Gandal"); 
GandalPtr->printName(); 
cout << GandalPtr.get() << endl;
return 0;
}

shared_ptr用法

Shared_ptr 指的是,允许多个ptr指向同1块内存,增加了1个reference 计数器

  • 当1个新指针指向该内存,reference计数器加1
  • 当1个指向从该内存移走后,reference 计数器减1
  • 计数器为0时,则释放内存对象。
    shared_ptr 适用于给函数传值,类对象引用等各类场景。
    在这里插入图片描述

创建shared_ptr 指针

std::shared_ptr<int> p1;               //不传入任何实参
std::shared_ptr<int> p2(nullptr);    //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10)); 

C++11 标准中还提供了 std::make_shared 模板函数,其可以用于初始化 shared_ptr 智能指针,例如:

// 指向int 数据
std::shared_ptr<int> p3 = std::make_shared<int>(10);
// 指向类对象
shared_ptr<Rectangle> p1(new Rectangle(10, 5));
p1->getArea()  //访问成员
//调用拷贝构造函数复制指针
std::shared_ptr<int> p2(p1); 
//或者 std::shared_ptr<int> p2 = p1;

用法示例

#include <iostream>
#include <memory>
using namespace std;int main()
{//构建 2 个智能指针std::shared_ptr<int> p1(new int(10));std::shared_ptr<int> p2(p1);//输出 p2 指向的数据cout << *p2 << endl;p1.reset();//引用计数减 1,p1为空指针if (p1) {cout << "p1 不为空" << endl;}else {cout << "p1 为空" << endl;}//以上操作,并不会影响 p2cout << *p2 << endl;//判断当前和 p2 同指向的智能指针有多少个cout << p2.use_count() << endl;return 0;
}

程序执行结果为:

10
p1 为空
10
1

weak_ptr 指针用法

weak_ptr不能单独使用,只能和 shared_ptr 类型指针搭配使用,区别是其内部无对象引用计数器。

在这里插入图片描述

使用方式:
(1) 先创建一个空 weak_ptr 指针,例如:
std::weak_ptr wp1;

将其指向 shared_ptr 指针变量,即与shared_ptr指向同1个内存对象

std::shared_ptr<int> sp (new int);
std::weak_ptr<int> wp3 (sp);

wp3与sp指向相同的内存区,由于 weak_ptr没有重载* 与->操作符,因此不能直接访问对象成员与方法。weak_ptr不会引起对象引用计数器的变化,如下

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;

如果要访问weak_ptr指向对象的成员或方法,需要借助 lock() 函数,返回一个和 weak_ptr 同指向的 shared_ptr 类型的指针,通过其来访问对象成员。

//访问对象的getArea()方法
cout << wp.lock()->getArea() << endl;
// 或者采用下面的方式,更安全。
auto sp = wp.lock() ;  
if (sp) {sp->getArea(); 
}

总结

为了避免C++程序产生内存泄露的风险,应该掌握 unique_ptr, shared_ptr, weak_ptr 3种智能指针类型的使用方式与应用场景,通过智能指针的特性来实现内存自动释放与回收。

http://www.lryc.cn/news/320007.html

相关文章:

  • Flutter 核心原理 - UI 框架(UI Framework)
  • Hive优化
  • React 的 diff 算法
  • 综合知识篇07-软件架构设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)
  • 【GPT-SOVITS-05】SOVITS 模块-残差量化解析
  • Flutter第四弹:Flutter图形渲染性能
  • [氮化镓]GaN中质子反冲离子的LET和射程特性
  • 【项目】C++ 基于多设计模式下的同步异步日志系统
  • 安卓国产百度网盘与国外云盘软件onedrive对比
  • 健身·健康行业Web3新尝试:MATCHI
  • VB.NET高级面试题:什么是 VB.NET?与 Visual Basic 6.0 相比有哪些主要区别?
  • 30.HarmonyOS App(JAVA)鸿蒙系统app多线程任务分发器
  • 伺服电机编码器的分辨率指得是什么?
  • WPF中使用LiveCharts绘制散点图
  • Android Studio实现内容丰富的安卓博客发布平台
  • 【GPT-SOVITS-01】源码梳理
  • 数据结构大合集02——线性表的相关函数运算算法
  • threejs案例,与静态三角形网格的基本碰撞, 鼠标环顾四周并投球游戏
  • 将FastSAM中的TextPrompt迁移到MobileSAM中
  • KY191 矩阵幂(用Java实现)
  • 基于Python的股票市场分析:趋势预测与策略制定
  • 【C++】了解一下编码
  • 生成式人工智能在金融领域:FinGPT、BloombergGPT及其未来
  • webpack5零基础入门-10babel的使用
  • SAR ADC教程系列5——FFT频谱泄露以及相干采样
  • 算法D48 | 动态规划10 | 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II
  • Windows10安装RubyRails步骤
  • Sqlserver 模糊查询中文及在mybatis xml【非中文不匹配查询】N@P2问题
  • 旧华硕电脑开机非常慢 电脑开机黑屏很久才显示品牌logo导致整体开机速度非常的慢怎么办
  • 【go语言开发】性能分析工具pprof使用