c++基础(六)——动态内存
在我们的程序中,静态内存——用来保存局部 static 对象,类 static数据成员,以及定义在任何函数之外的变量。栈内存——用来保存定义在函数内的非 static 对象。分配在 静态内存 或 栈内存中的对象由编译器自动创建和销毁。对于栈内存,仅在其定义的程序块运行时才存在,static对象在使用之前分配,在程序结束时销毁。
除此之外,每个程序还拥有一个内存池,这部分内存被称为自由空间(堆),程序用堆来存储动态分配的对象,——即那些在程序运行时分配的对象。
1. 动态内存和智能指针
在C++中,动态内存的管理是通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态指针,销毁该对象,并释放与之关联的内存。
新的标准提供了两种智能指针(smart pointer)类型来管理动态对象。shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,指向shared_ptr所管理的对象。这三种类型都定义在memory中。
1.1 share_ptr 类
类似vector智能指针也是模板。
shared_ptr<string> p1; //shared_ptr,可以指向string
shared_ptr<list<int>> p2; //shared_ptr,可以指向int的list
智能指针的使用方法和普通指针类似,解引用返回它指向的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空,
// 如果 p1 不为空,检查它是否指向一个空 string
if (p1 && p1->empty()) // p->mem -- (*p).mem
*p1 = "ds"
1.2 make_shared 函数
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数。此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。与智能指针一样,make_shared也定义在memory中。
//指向一个值为42的int的shared_ptr
shared_ptr<int> p3 = make_shared<int>();
//p4指向一个值为”999999999”的string
shared_ptr<string> p4 = make_shared<string>(,'');
//p5指向一个值初始化的int,即,值为0
shared_ptr<int> p5 = make_shared<int>();
auto p6 = make_share<vector<string>>();
1.3 share_ptr 的拷贝和赋值
当进行拷贝或赋值操作时,每个shared_ptr都会记录有多少个其他shared_ptr指向相同的对象:
auto p = make_shared<int>(); //p指向的对象只有p一个引用者
auto q(p); //p和q指向相同对象,此对象有两个引用者
我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数(reference count)。无论何时我们拷贝一个shared_ptr,计数器都会递增;当我们给shared_ptr赋予一个新值或是shared_ptr被销毁时,计算器就会递减。
一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象:
auto r = make_shared<int>(); //r指向的int只有一个引用者
r = q; //给r赋值,令它指向另一个地址
//递增q指向的对象的引用计数
//递减r原来指向对象的引用计数
//r原来指向的对象已没有引用者,会自动释放
1.4 share_ptr 自动销毁所管理的对象
当指向一个对象最后一个 share_ptr 被销毁时,share_ptr 类会自动销毁此对象。它是通过另一个特殊的成员函数——析构函数完成销毁工作的。
2. shared_ptr 和 new 结合使用
我们可以使用 new 返回的指针来初始化智能指针,智能指针是一个类,分装了一个原始的 C++ 指针,用以管理所指对象的生命期。
shared_ptr<double> p1; //shared_ptr可以指向一个double
shared_ptr<int> p2(new int ()); //p2指向一个值为42的int
接受指针参数的智能指针构造函数是explicit的。因此,我们不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化形式来初始化一个智能指针:
shared_ptr<int> p1 = new int(); //错误:必须使用直接初始化形式
shared_ptr<int> p2(new int ()); //正确:使用了直接初始化
出于相同的原因,一个返回shared_ptr的函数不能在其返回语句中隐式转换一个普通指针:
shared_ptr<int> clone(int p){
return new int(p); //错误:隐式转换为shared_ptr<int>
}
shared_ptr<int> clone(int p){
return shared_ptr<int>(new int(p)); //正确:显式地用int*创建shared_ptr<int>
}
默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。我们可以将智能指针绑定到一个指向其他类型的资源的指针上,但是为了这样做,我们必须自己提供操作来代替 delete 。

c++基础(六)——动态内存的更多相关文章
- C和C指针小记(十六)-动态内存分配
动态内存分配 1.1 为什么使用动态内存分配 直接声明数组的方式的缺点: 1) 声明数组必须指定长度限制.无法处理超过声明长度的数组. 2) 如果声明更大的常量来弥补第一个缺点,会造成更多的内存浪费. ...
- C++基础之动态内存
C++支持动态分配对象,它的生命周期与它们在哪里创建无关,只有当显示的被释放时,这些对象才会被销毁.分配在静态或栈内存中的对象由编译器自动创建和销毁. new在动态内存中为对象分配空间并返回一个指向该 ...
- 数据结构基础(1)--数组C语言实现--动态内存分配
数据结构基础(1)--数组C语言实现--动态内存分配 基本思想:数组是最常用的数据结构,在内存中连续存储,可以静态初始化(int a[2]={1,2}),可以动态初始化 malloc(). 难点就是数 ...
- 必须要注意的 C++ 动态内存资源管理(六)——vector的简单实现
必须要注意的 C++ 动态内存资源管理(六)——vector的简单实现 十六.myVector分析 我们知道,vector类将其元素存放在连续的内存中.为了获得可接受的性能,vetor ...
- 数据结构基础——指针及动态内存分配(malloc)
一.指针 C语言中的指针是一种数据类型,比如说我们用int *a;就定义了一个指针a,它指向一个int类型的数.但是这个指针是未初始化的,所以,一般的,我们都在创建指针时初始化它,以免出错,在还不吃的 ...
- C/C++基础----动态内存
why 管理较难,忘记释放会内存泄漏,提早释放可能非法引用,重复释放. 为了更容易,更安全的使用动态内存,提供智能指针,其默认初始化保存一个空指针. what shared_ptr允许多个指针指向同一 ...
- C语言之动态内存管理
C语言之动态内存管理 大纲: 储存器原理 为什么存在动态内存的开辟 malloc() free() calloc() realloc() 常见错误 例题 柔性数组 零(上).存储器原理 之前我们提到了 ...
- C++——类和动态内存分配
一.动态内存和类 1.静态类成员 (1)静态类成员的特点 无论创建多少对象,程序都只创建一个静态类变量副本.也就是说,类的所有对象都共享同一个静态成员. (2)初始化静态成员变量 1)不能在类声明中初 ...
- 转: Linux C 动态内存分配 malloc及相关内容 .
一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针 ...
随机推荐
- web大附件上传,支持断点续传
一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...
- 认识Nodejs
一.概念 ①JavaScript运行环境:Node.js不是一门语言,不是库也不是框架,是一个JavaScript运行环境,简单点来讲就是Node.js可以解析执行JavaScript代码,也就是说J ...
- 72: libreoj #10147 区间dp
$des$ 将 n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆.规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分. 请编写一个程序,读入堆数 nnn 及每堆的石子数 ...
- mysql开放远程连接
1.检查端口是否被监听,没有的话请启动mysql. netstat -atnp | grep 3306 2.检查用户是否具备远程连接,即host字段值不是 % mysql -uroot -p你的密码 ...
- 第12组 Alpha冲刺(6/6)
Header 队名:To Be Done 组长博客 作业博客 团队项目进行情况 燃尽图(组内共享) 展示Git当日代码/文档签入记录(组内共享) 注: 由于GitHub的免费范围内对多人开发存在较多限 ...
- win10 自带计算器删除了怎么办
win+S后输入Powershell,以管理员身份运行后,使用下面的命令:重要的说三遍:以管理员身份运行!以管理员身份运行!以管理员身份运行!Get-AppxPackage *calculator* ...
- 多线程 interrupt()方法
java interrupt()方法只是设置线程的中断标记,当对处于阻塞状态的线程调用interrupt方法时(处于阻塞状态的线程是调用sleep, wait, join 的线程),会抛出Interr ...
- 【大数据应用技术】作业九|安装关系型数据库MySQL 安装大数据处理框架Hadoop
本次作业的要求来自:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3161 1.安装MySql 按ctrl+alt+t打开终端窗口,安 ...
- mongodb设置 十个要点
mongodb设置 十个要点 一.对象ID的生成 每一个mongoDB文档那个都要求有一个主键.它在每一个集合中对全部的文档必须是唯一的.主键存放在文档_id字段中.由12个字符组成: 4c291 ...
- Netty回调与Channel执行流程分析
在上一篇的基础上修改代码 1.TestHttpServerHandle 类 package com.example.firstexample; import io.netty.buffer.Byte ...