首页 > 系统相关 >指针与内存管理

指针与内存管理

时间:2023-06-06 22:11:14浏览次数:45  
标签:std 管理 内存 shared unique ptr 指针

参考文章:
《现代 C++:一文读懂智能指针》 https://zhuanlan.zhihu.com/p/150555165
《当我们谈论shared_ptr的线程安全性时,我们在谈论什么》 https://zhuanlan.zhihu.com/p/416289479

指针

指针是C++中一种内置变量类型,存放内存地址

// 局部变量,存储空间静态分配
int a;
int *p = &a;
delete p; // 报错

// 内存动态分配,用指针存储内存首地址
int *p = new int(42);
// 释放内存:只有动态内存管理中的地址指针才能delete
delete p;

内存管理

(1)静态内存分配:局部变量、全局/静态变量,不需要且不能手动释放的内存。静态内存分配的缺陷是内存使用不够灵活,不能及时释放内存,内存使用效率底

(2)动态内存管理方式:直接内存管理(new/delete)、智能指针管理(unique_ptr/shared_ptr)

  • 直接内存管理:new/malloc主动申请的内存,资源存放于堆/内存映射区,指针接收 new 分配的内存空间首地址;delete + 指针名 释放内存,可以也必须手动释放内存
  • delete释放内存,会调用内存中类的析构函数,如果类中依然存在动态资源,则在析构函数中通过delete进一步删除。直接内存管理的缺陷是易出现内存泄漏、野指针
  • 智能指针管理内存:指针变量生命周期结束时自动释放指针指向的资源,安全性更高

智能指针细节分析

智能指针封装为类,用来智能管理内存,指针对象生命周期结束时自动释放其管理的资源,不需要手动释放

API:定义、初始化、拷贝赋值、其他函数接口,忽略,不记得可以去查书

与普通指针一样,智能指针既可指向动态申请的内存,也可指向静态局部变量

  • 指向动态分配内存空间时默认使用 delete 释放资源
  • 指向静态资源时,无法通过 delete 释放资源,需要自定义删除器。删除器指定了在指针生命周期结束时要对静态资源做什么操作(RAII的体现)

shared_ptr

shared_ptr共享式管理资源,允许多个shared_ptr指向同一资源

shared_ptr基本原理:通过指针共享资源,指向资源的指针数量为0时自动释放资源

// 通过 shared_ptr 管理的资源有两种初始化方式

// 使用 new 初始化
std::shared_ptr<T> ptr1 (new T);

// 使用 make_shared 初始化智能指针
std::shared_ptr<T> ptr2 = make_shared<T>();

imgimg

(1)定义的指针对象(存放在栈中)中有两个内置指针成员变量,它们分别指向:共享资源、控制信息

(2)通过new初始化智能指针,会动态分配两次内存,两块内存分别存放:共享资源、控制信息

控制信息中包含:指向共享资源的shared_ptr/weak_ptr的个数(引用计数)、默认/自定义删除器、指向共享资源的指针;

通过make_shared初始化智能指针,内存只分配一次,共享资源与控制信息存放到同一块内存中,且控制信息中不必再存放指向共享资源的指针。

weak_ptr:unique_ptr的替代,指向资源的shared_ptr数量为0时,不管有没有weak_ptr指向资源,均会释放。解决unique_ptr循环引用问题。

线程安全

线程安全否?多线程操作同一个shared_ptr时是否会出现不一致的情况?例如有两个线程对同一个shared_ptr进行赋值或拷贝,引用计数会不会只加了1?

考虑赋值过程:

std::shared_ptr<int> sptr1 = std::make_shared<int>(42);
std::shared_ptr<int> sptr2 = std::make_shared<int>(42);

std::shared_ptr<int> sptr3(sptr1); // 情形1:sptr1 管理的对象引用计数加一

sptr1 = sptr2; // 情形2:sptr1 重新指向 sptr2管理的对象

情形1:管理同一个数据的shared_ptr在进行引用计数的增加或减少时是线程安全的,因为对引用计数的操作是原子操作

情形2:考虑赋值过程,sptr1管理对象的引用计数减一,sptr2管理对象的引用计数加一,这个过程也是线程安全的

再考虑智能指针管理的数据的线程安全性。例如多线程通过shared_ptr 共享同一vector,对其进行push_back可能造成内存错误(多线程并发引起)

unique_ptr

unique_ptr独占它管理的资源。

{
    // 初始化unique_ptr
    unique_ptr<int> p1 (new int(42));

    // unique_ptr不支持普通的拷贝与赋值
    
    unique_ptr<int> p2(p1);	// 错误,不支持拷贝
    unique_ptr<int> p3;
    p3 = p1;	// 错误,不支持赋值
}

一个例外:当unique_ptr是一个将亡值(返回值)时,可以对其进行拷贝或将其值赋给新的 unique_ptr。或者使用std::move将unique_ptr主动转化为一个右值(将亡值),然后可进行拷贝或赋值:

{
    std::unique_ptr<int> uptr = std::make_unique<int>(200);
    std::unique_ptr<int> uptr1 = uptr;  // 编译错误,std::unique_ptr<T> 是 move-only 的

    std::unique_ptr<int> uptr2 = std::move(uptr); // uptr将亡时才能拷贝它 或被其赋值
    assert(uptr == nullptr);
}

标签:std,管理,内存,shared,unique,ptr,指针
From: https://www.cnblogs.com/essays/p/17461884.html

相关文章

  • 增效又灵活的在线快速开发平台,助力企业进入流程化管理!
    一直有不少粉丝随时来询问:企业要想做好数据管理,从此进入流程化管理,可以选择什么样的平台软件?众所周知,在数字化转型发展时期,在线快速开发平台凭借其灵活、简便、易操作等优势特征,成为提升企业办公协作效率,提升表格制作水平,做好数据管理的重要助手。关键是如何选择服务商,如何选择适......
  • 指针计算详解
    intmain(){ inta[5]={1,2,3,4,5}; int*ptr=(int*)(&a+1);//&a+1跳过整个数组后的地址数组类型转换后存入*ptr printf("%d\n",*(ptr-1));//ptr-1解引用获得的是a[5]的值 p=(structtest*)0x100000; printf("struct大小=%d\n",sizeof(*p));//结构体大小是24......
  • 第五节 5with管理文件操作上下文
    在Python中,进行文件操作时,需要打开文件、读写文件、关闭文件等过程。如果代码有错误或者忘记关闭文件就会导致程序出错或文件资源泄露问题。为了更方便、更安全地进行文件操作,Python提供了with语句来管理文件的操作上下文。使用with语句可以确保在任何情况下,文件都会被正确地关闭......
  • 指针进阶(上)
    前言本章介绍指针进阶上半部分。1、字符指针2、数组指针3、指针数组4、数组传参和指针传参在讲解指针进阶前我们先复习一下,指针的一些基本概念:(1)指针是一个变量,用来存放地址,这个指针唯一标识一块内存空间。(2)指针的大小(所占的空间的大小)固定是4/8个字节,在32/64位环境下会有......
  • Python 练手小项目-名片管理
    需求描述需要写一段程序实现简单名片管理功能程序启动展示主界面新建名片显示全部查询名片退出系统主程序实现'''名片管理系统主程序'''importcards_toolswhileTrue:'''显示主界面'''cards_tools.show_menu()action=input('请选择操作功能:�......
  • 时间管理四象限法怎么运用?这款待办工具来帮你
    在现代职场中,时间就是金钱,而大多数企业对员工的要求也是在规定的工作时间内完成尽可能多的工作任务。这就表示对于上班族来说,时间管理是非常重要的,而谈到时间管理就不得不提到一个重要的时间管理法则了,它就是“时间管理四象限法则”。时间管理四象限法,简单来说就是将你每天需要完......
  • 使用JOL查看java对象内存结构
    JOL(JavaObjectLayout)工具包可以展示java对象在jvm中的结构信息,用来进行内存分析。是由openjdk提供的小工具包。git地址https://github.com/openjdk/jol。因此下面的测试基于hotspot虚拟机环境下。添加依赖<dependency><groupId>org.openjdk.jol</group......
  • U8物料启用批次管理,出库存在批号无法出库的处理,提示没有批次管理,请不要输入批号
    场景:A物料原来有批次管理,在入库时库存做了批次号,但后来取消了批次管理,这时出库当前物料会提示没有批次管理,请不要输入批号。物料无法出库。这里可以采取简单方法:此时存货档案这里已无法勾上批次管理,会提示已在库存管理中使用。请按以下两步操作进行:首先我们登陆数据据库SQL管......
  • 中企出海,海外税务管理体系怎么设计?
    一、海外税务管理工作的全貌面对海外税务管理工作,首先回答三个问题:第一,我们要管什么;第二,到底碰到什么问题;第三,怎么管。从第一个问题开始,我们管理的工作内容到底是什么?具体可分了五层,从下往上看。第一层税务合规工作。在海外的税务合规工作包括税务的登记、税务的注销、境外财务帐号......
  • 24基于java的宠物医院管理系统
    项目背景随着互联网的普及,已经和我们的生活不可分割;宠物渐渐的已经成为了我们的好朋友,宠物医院管理系统可以帮助用户合理的管理宠物,呵护宠物的健康,对宠物起到了一个健康监控的作用;项目介绍系统总体分为3个角色:分别是系统管理员;医生和用户;不能的角色拥有不同的功能权限,下面详......