首页 > 编程语言 >C++ Primer学习笔记——第十二章

C++ Primer学习笔记——第十二章

时间:2023-11-18 16:55:05浏览次数:42  
标签:指向 对象 第十二章 C++ 内存 shared Primer ptr 指针

第十二章 动态内存

前言

在此之前,我们使用的程序中对象都有着严格定义的生存期:

  • 全局对象,在程序启动时分配,在程序结束是销毁。
  • 局部自动对象,当进入定义所在程序时创建,在离开块时销毁。
  • 局部static对象,在第一次使用前分配,在程序结束时销毁。

显然这存在限制,为此C++支持动态分配对象。动态分配对象的生存期与它们在哪里创建无关,只有当显式地被释放时,这些对象才会被销毁。

动态对象的正确释放被证明时编程中极其容器出错的地方。那么为了更安全释放,标准库定义了两个智能指针来管理动态分配的对象。当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。

静态内存:局部static对象、类static数据成员以及定义在任何函数之外的变量

栈内存:定义在函数内的非static对象

分配在静态或栈内存的对象由编译器自动创建和销毁。除了静态内存和栈内存,每个程序还拥有一个内存池。称为自由空间,程序用堆来存储动态分配(dynamically allocate)的对象——即那些在程序运行时分配的对象。

动态内存和智能指针

在C++中,动态内存的管理通过一对运算符完成:

  • new,在动态内存中为对象分配空间并返回一个指向对象的指针,可以选择对对象初始化
  • delete,接受一个动态对象的指针,销毁指针指向对象,并释放与之关联的内存

但是动态内存的使用容易出问题,难以确保在正确时间释放内存,那么就可能出现“内存泄露”、“引用非法指针”等。对此,标准库引入两种智能指针(smart pointer):

  • shared_ptr,允许多个指针指向同一个对象
  • unique_ptr,独占所指向的对象

智能指针的行为类似常规指针,区别在于智能指针负责自动释放所指向的对象。上述的两种指针区别在于管理底层指针的方式不同。

同时,标准库还定义了一个weak_ptr的伴随类,其是一个弱引用,指向shared_ptr所管理的对象。三者均定义在memory头文件中。

shared_ptr类

智能指针为模板,在创建时需要提供额外的信息表明指针可以指向的类型。

shard_ptr<string> p_1;
shard_ptr<list<int>> p_2;
shared_ptr和unique_ptr都支持的操作 解释
shared_ptr sp
unique_ptr up
空智能指针,可以指向类型为T的对象
p 将p用作一个条件判断,若p指向一个对象,则为true
*p 解引用p,获得它指向的对象
p->member 等价于(*p).member
p.get() 返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了
swap(p,q)
p.swap(q)
交换p和q中的指针
shard_ptr独有的操作 解释
make_shared(args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
shared_ptrp(q) p是shared_ptr q的拷贝。此操作会递增q中的计数器。q中的指针必须能转化为T*
p=q p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放
p.unique() 若p.use_count()为1,返回true,否则返回false
p.use_count() 返回与p共享对象的智能指针数量;可能很慢,主要用于调试

make_shared函数

最安全的分配和使用动态内存的方法是调用make_shared标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。

shared_ptr<int> p_3=make_shared<int>(42); // 指向一个值为42的int
shared_ptr<string> p_4=make_shared<string>(2,'9'); // 指向一个值为“99”的string
shared_ptr<int> p_5=make_shared<int>(); // 指向一个值初始化的int

shared_ptr的拷贝和赋值

当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象:

auto p=make_shared<int>(42); // p指向的对象只有p一个引用者
auto q(P); // p和q指向相同对象,此对象有两个引用者

我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。无论何时拷贝一个shared_ptr,计数器都会递增。例如,当用一个shared_ptr初始化另一个shared_ptr,或将它作为参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减。

当一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:

auto p = make_shared<int>(42); // p指向的int只有一个引用者
p = q; // 给p赋值,令它指向另一个地址
	   // 递增q指向的对象的引用计数
	   // 递减p原来指向的对象的引用计数
	   // p原来指向的对象已经没有引用者,会自动释放

标签:指向,对象,第十二章,C++,内存,shared,Primer,ptr,指针
From: https://www.cnblogs.com/aaroncoding/p/17840726.html

相关文章

  • C++ 观察者模式实现
    观察者模式主体(被观察者)通知一个或多个观察者状态改变/数据更新/事件发生。描述C++实现观察者模式有几个要点:观察者都有一个共同的抽象基类Listener,定义了一个纯虚接口OnNotified(),主体调用该接口通知观察者每个观察者ConcreteListener继承自抽象基类Listener,并实现......
  • C/C++ 运用VMI接口查询系统信息
    WindowsManagementInstrumentation(WMI)是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口,通过这个接口,可以获取有关计算机系统硬件、操作系统和应用程序的信息,以及对系统进行管理和控制的能力。WMI允许通过编程方式查询系......
  • L1-6 吉老师的回归 (15 分)(C/C++)
    输入样例1:51L1-1isaqiandaoproblem.L1-2isso...easy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,soeasy.输出样例1:L1-4isqianDao.输入样例2:54L1-1isa-qiandaoproblem.L1-2issoeasy.L1-3isEasy.L1-4isqianDao.Wow,suchL1-5,so!!easy.输出样例......
  • 创建顺序表(C++)
    include<stdio.h>defineMaxSize10 //定义最大长度//创建顺序表typedefstruct{intdata[MaxSize]; //创建数组data用来储存数据元素,并将data的长度设置为MaxSizeintlength; //顺序表的当前长度}SqList;//初始化顺序表voidInitList(SqList&L){for(inti=0;i<......
  • c++日志库-log4cplus
    《log4cplus日志库》1.Preface  log4cplus是一款开源的c++日志库,具有线程安全,灵活,以及多粒度控制的特点;log4cplus可以将日志按照优先级进行划分,使其可以面向程序的调试,运行,测试,后期维护等软件全生命周期;可以通过配置,选择将日志输出到屏幕,文件,NTeventlog,甚至是远程服务器......
  • 5 步在 Ubuntu22 上使用 C++20
    1.安装build-essentialsudoaptinstallbuild-essential安装完检查/usr/bin/下是否有gcc,g++,gcc-11,g++11.2.添加ppa源sudoadd-apt-repositoryppa:ubuntu-toolchain-r/test3.安装gcc-13和g++-13sudoapt-getinstallgcc-13sudoapt-getinstallg++-......
  • C++ STL 容器底层实现
    一、关键词I:容器1、顺序容器:底层是链表和数组array(数组)、vector(可变数组)、deque(双端队列)forward_list(单向链表)、list(双向链表)2、关联容器:底层是红黑树set(集合)、mulitset(可重复元素的集合)map(字典)、multimap(可重复键值的字典)3、无序关联......
  • C++线程
    进程以CPU为运行单位,多个CPU可以实现进程并行,单个CPU可以实现进程并发(进程调度)线程以CPU的核心为运行单位,多个CPU内核可以实现线程并行,单个内核可以实现线程并发(线程调度)1、创建和结束一个线程 #include<iostream>#include<pthread.h>///@brief创建一个线程///@param......
  • C++类与继承
    C++类有三种访问修饰符:public(共有的)、private(私有的)、protected(受保护的)类内各区域成员的访问:1、public类内成员函数、类外、友元函数都可以访问。2、private类内成员函数、友元函数可以访问,private区域成员不能在派生类中访问。3、protected与private不同之......
  • 第十四届蓝桥杯省赛 C++B组 ---- 景区导游
    第十四届蓝桥杯省赛C++B组----景区导游LCA原题连接​ lca同时得到按原来路径走的总时间​ 最后输出时处理跳过某个点的时间​ 预处理用bfs或dfs都可以importjava.io.BufferedReader;importjava.io.InputStreamReader;importjava.util.Arrays;importjava.......