首页 > 编程语言 >【C++11】智能指针

【C++11】智能指针

时间:2024-12-31 18:57:40浏览次数:3  
标签:11 people 对象 C++ shared unique ptr 指针

目录

指针

  • 普通指针:指向内存区域的地址变量
  • 当普通指针指向动态分配的内存的时候,即使这个指针变量离开了所在的作用域,这块内存也不会被自动销毁,动态分配的内存不进行释放,则造成了内存泄漏。
    在这里插入图片描述
  • 如果一个指针指向了一块已经被释放的内存区域,那么这个指针就是悬空指针,使用悬空指针会造成不可预料的结果。
    在这里插入图片描述
  • 定义了一个指针,却未初始化使其指向有效的内存区域时,这个指针就成了野指针,使用野指针访问内存,一般会造成segmentation fault 错误。
    在这里插入图片描述
  • 智能指针:封装了动态对象指针的类对象

使用智能指针,则可以有效的避免上述问题的发生。
智能指针是一个对象,它封装了指向另一个对象的指针,当智能指针离开作用域后,会被自动销毁,销毁过程中会调用析构函数来删除所封装的对象。
在这里插入图片描述

标准库

在标准模板库中提供了以下几种智能指针:

  • unique_ptr
  • shared_ptr
  • weak_ptr

unique_ptr

在创建智能指针时,你可以传入一个指向对象的类型和自定义的删除器,(删除器一般为默认不传)。
Deleter 是一个模板类,它用于定义如何释放智能指针管理的对象,可以被作为删除器。
在这里插入图片描述

unique_ptr与它所管理的动态对象是一对一的关系,不能有两个unique_ptr同时指向同一个地址。

对应类方法

  • get() — 用于获取所管理对象的指针
  • 重载的-> 成员运算符函数 — 调用了get函数,也是返回了所管理对象的指针
  • 重载的*成员运算符 — 返回所管理对象的引用,相当于*get()
  • reset(T* newObject) — 会删除原有的对象,接管新的对象。
  • swap(unique_ptr<T>& other) — 交换所管理的对象

在这里插入图片描述

创建unique_ptr对象的两种方法

ptr1 指向new出来的对象。

	unique_ptr<A> ptr1(new A(参数))

	unique_ptr<A> ptr1 = make_unique<A>(参数)

unique_ptr的使用

  • 当unique_ptr 不再指向当前对象的时候,会自动删除对象。
#include <iostream>
using namespace std;

class Rectangle {
public:
	Rectangle(double w, double h) :width(w),height(h){}
	~Rectangle() { cout << "对象被释放" << endl; }
	double area() { return width * height; }
private:
	double width;
	double height;
};


int main()
{
	unique_ptr<Rectangle> pDemo(new Rectangle(3.5, 4.1));
	pDemo = nullptr;
	cout << "分隔-------分隔"  << endl; //是否在这之前就将对象释放
	return 0;
}

特性

  • 由于unique_ptr 对所管理的资源具有独占性,所以unique_ptr的特性有不能被拷贝,不能被赋值。
  • 但可以通过move转移
  • 一般智能指针的大小与指针是相同的

shared_ptr

多个shared_ptr对象可以共同管理同一个指针。
它们通过一个共同的引用计数器来管理指针,例如,当有3个shared_ptr都指向一个对象时,引用计数器的值为3,当一个智能指针被销毁时,引用计数器-1,当计数器为0时,会将所指向的内存对象释放。

类方法

use_count — 获得有多少个shared_ptr在共同管理同一个对象
unique — 返回use_count是否等于1
在这里插入图片描述
在这里插入图片描述

循环引用造成内存泄漏

  • 以下代码均有两个智能指针分别指向张三,李四,王五。
  • 当people离开作用域被销毁后,会将每个Person对象的引用计数-1,但是每个Person对象的成员partner智能指针仍存在,所以无法自动删除person对象,导致内存泄。
class Person
{
public:
	Person(const string& name) :_name(name) { cout << "构造函数调用" << endl; }
	~Person() { cout << _name << "销毁" << endl; }
	void setPartner(const shared_ptr<Person>& other) { _partner = other; }
private:
	string _name;
	shared_ptr<Person> _partner;

};

int main()
{
	vector<shared_ptr<Person>> people;
	people.push_back(shared_ptr<Person>(new Person("张三")));
	people.push_back(shared_ptr<Person>(new Person("李四")));
	people.push_back(shared_ptr<Person>(new Person("王五")));

	people[0]->setPartner(people[1]);
	people[1]->setPartner(people[2]);
	people[2]->setPartner(people[0]);

	return 0;
}

weak_ptr

用来表示临时所有权,不会增加引用计数,需要结合shared_ptr使用。当需要临时所有权时,则将其转换为shared_ptr,这样对象的引用计数会+1,来保证正在访问对象的有效性。

weak_ptr的创建

  • 可以将一个share_ptr作为weak_ptr的构造函数参数来初始化。
  • 也可以直接将share_ptr赋值weak_ptr。
    在这里插入图片描述

三个方法

  • use_count() — 返回引用计数
  • expired() — 用来检查与之关联的对象是否已经被销毁。如果对象已经被销毁(即 shared_ptr 的引用计数为 0),那么 expired() 返回 true;否则,返回 false。
  • lock() — 用于尝试将一个 weak_ptr 转换为 shared_ptr。如果 weak_ptr 观察的对象仍然存在(即 shared_ptr 的引用计数大于 0),那么 lock() 会返回一个有效的 shared_ptr,指向相同的对象。如果对象已经被销毁(引用计数为 0),那么 lock() 返回一个空的 shared_ptr。

功能

控制块是在share_ptr第一次接管对象的时候创建的。
shared_ptr 决定 use_count 的值。
weak_ptr 决定 weak_count 的值。
当use_count值等于0时,释放对象。
在这里插入图片描述

例子1

  • w_p1不增加引用计数
  • s_p1,s_p2指向对象rectangle,所以计数为2。
  • 当退出作用域时,引用计数为0,释放对象。
    在这里插入图片描述

例子2

  • 创建临时所有权
  • 当引用计数>0时,返回有效的shared_ptr
  • 当引用计数为0时,返回空
    在这里插入图片描述

标签:11,people,对象,C++,shared,unique,ptr,指针
From: https://blog.csdn.net/qq_72680384/article/details/144852628

相关文章

  • rust学习十五.3、智能指针相关的Deref和Drop特质
     一、前言智能指针为什么称为智能指针?大概因为它所包含的额外功能。这些额外的功能使得编码或者运行时让指针看起来更有效、并体现某些“智”的特征,所以,我猜测这应该是rust发明人这么称呼此类对象为智能的原因。 据前面有关章节所述,我们知道智能指针多基于结构体(struct)扩......
  • C++ 游戏开发技术文档
    项目概述本技术文档将指导开发一个使用C++构建的简易2D游戏框架。该游戏是一个玩家控制角色收集随机生成的道具的小游戏,核心功能包括:游戏循环:支持帧率控制和逻辑更新。玩家控制:通过键盘控制角色上下左右移动。道具生成与收集:随机生成道具,玩家接触道具后得分。基本碰撞......
  • SubInAcl 版本 5.2.3790.1180
    下载 SubInAcl工具按功能分类的表格:功能分类命令选项描述输出日志和错误日志/outputlog=文件名<br>/errorlog=文件名指定输出和错误日志文件名显示详细信息/verbose (默认)<br>//noverbose显示详细信息或不显示详细信息测试模式/testmode<br>//not......
  • yolov5单目测距与相机标定流程和c++单目测距RKNN部署
    相机模型、相机标定及基于YOLOv5的单目测距实现1.前言注意此方法不需要预先知道物体尺寸,不需要参照物体!!!!在摄像头成像的过程中,物体反射的光线通过摄像头的凸透镜聚焦到成像器件上,形成一张二维图像。这一过程将三维世界中的物体转换为二维图像,导致深度信息丢失,因此单目摄......
  • YOLOv11在劳保用品检测中的应用:从原理到训练与部署(yolo11防护服/安全帽/安全鞋/反光
    YOLOv11在劳保用品检测中的应用:从原理到训练与部署YOLOv11在劳保用品检测中的应用:从原理到训练与部署(yolo11防护服/安全帽/安全鞋/反光衣/手套/劳保用品检测)一、YOLOv11简介及工作原理YOLO(YouOnlyLookOnce)系列算法是目标检测领域中的一种快速且准确的实时检测方法。......
  • 玩一玩 yolo v11
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯记录体验yolov11的过程:1.下载镜像dockerpullultralytics/ultralytics这个镜像有11GB2.进入镜像的bashdockerrun-it--name=yolov11_test-v~/Picture......
  • LeetCode算法题 (比较含退格的字符串)Day9!!!C/C++
    https://leetcode.cn/problems/backspace-string-compare/description/一、题目描述给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。注意:如果对空文本输入退格字符,文本继续为空。二、相关知识点了解   ......
  • 11.23
    学习了数据库设计的基本步骤,包括需求分析、概念设计(绘制ER图)、逻辑设计(将ER图转换为关系模式)和物理设计(确定数据库的存储结构和索引策略)。通过一个小型项目的数据库设计案例,实践了整个数据库设计流程,深刻体会到了合理的数据库设计对于软件系统性能和数据完整性的重要性。同时,......
  • 11.20
    importjavafx.application.Application;importjavafx.geometry.Insets;importjavafx.scene.Scene;importjavafx.scene.control.Button;importjavafx.scene.control.Label;importjavafx.scene.control.TextArea;importjavafx.scene.layout.VBox;importjavafx.st......
  • 11.18
    类图(ClassDiagram)用途:类图是UML中最常用的图之一,用于描述系统中的类、类的属性、操作以及类之间的关系。它是对系统静态结构的一种直观展示,有助于理解系统的架构和设计模式。元素构成:类(Class):用矩形表示,分为三层,最上层是类名,中层是属性(格式为[可见性]属性名:类型,如“-......