C++内存管理-new,delete,new[],placement new的简单使用
技术在于交流、沟通,本文为博主原创文章转载请注明出处并保持作品的完整性
首先,我们先看一下C++应用程序,使用memory的途径如下图所示

C++应用程序中申请内存基于分配器的实现(std::allocator),而分配器基于C++primitives(new,new[]...),c++primitives基于C语言中的malloc/free..,当然越底层的函数效率越高.
那我们会想,直接用最底层的实现多好,效率还高.但如果你直接调用底层的函数去实现功能,虽然你的效率提高了,但你的程序的可移植性就会相应的降低.
不可否认底层语言的实现,体现出一定的个人能力.但过多的篇幅去实现底层语言,会影响开发效率.
下面说一下C++三种申请内存的工具,然后介绍一下这三种工具的简单使用
A.new operator, delete operator : 申请内存+构造函数
B.new[], delete[] : 用于数组类的操作
C.placement new : 定点new
一 new operator, delete operator,
分配内存的函数的对应关系如下图,下面主要介绍一下下面这些函数的简单使用

int main()
{
void* p1 = malloc(); //512bytes
free(p1); complex<int>* p2 = new complex<int>; //one object
delete p2; void* p3 = ::operator new();// 512bytes
::operator delete(p3); //一下函数都是non-static,一定要通过object调用,分配7个int的内存
void* p4 = allocator<int>().allocate();//allocator<int>()创建临时对象
allocator<int>().deallocate((int*)p4,); return ;
}
我们都知道 new = operator new + 构造函数,delete = 析构函数 + operator delete .如果以代码的形式表现出来应该是这样
比如我们创建一个复数类,
Complex* pc = new Complex(,);
那么编译器会将上面的代码翻译成
try
{
void* mem = operator new(sizeof(Complex)); //allocate pc = static_cast<Complex*>(mem); //cast pc->Complex::Complex(,); //只有编译器可以直接调用构造函数 }
catch (std::bad_alloc)
{
//申请内存失败...
}
释放内存
delete pc;
编译器翻译为
pc->~Complex();//先调用析构函数
operator delete(pc);// operator delete的实现基于free()
二 new[]和delete[]
new[],主要运用于数组的申请内存,
如class A 当我们调用
A* p = new A[];//那么就会申请3个class A的内存并调用3次 class A的构造函数
当我们调用 delete[]时
delete[] p; //就会调用3次析构函数 并释放内存(3个class A的内存)
如果我们释放时没有加[]
delete p;
它同样会释放3个class A的内存,但是之后调用其一个构造函数(如果其构造函数内有其他释放内存的操作,那么我们不加[]就会造成内存泄漏)
看一下测试代码
class A
{
public:
int id; A() : id()
{
cout << "default ctor.this=" << this << " id=" << id << endl;
} A(int i): id()
{
cout << "ctor.this=" << this << " id=" << id << endl;
} ~A()
{
cout << "dtor.this=" << this << " id=" << id << endl;
}
};
测试
void test_class()
{
A* buf = new A[]; //默认构造函数调用3次 调用顺序 0-1-2
//A必须有默认构造函数 引文new A[3]调用的是默认构造函数 A* tmp = buf;//记录A数组的起点位置 cout << "buf=" << buf << " tmp=" << tmp << endl; for(int i = ; i < ; i++)
{
new(tmp++)A(i); //placement new
} cout << "buf=" << buf << " tmp=" << tmp << endl; delete[] buf;
}
输出结果

我们会发现 delete[] 的顺序与 new[] 的顺序相反,placement后面再说
那么我们这个使用不写[]呢,看看输出结果会怎么样

上面的delete 没有写[], 3个class A的内存是释放了,但是只调用了一次析构函数.
三 placement new
placement new允许我们将object创建与 已经申请好的内存中,但是没有所谓的 placenment delete,因为根本没有分配内存,所以没有placement delete
但是有被称作的placement delete后面说.先看一下placement new
char* buf = new char[sizeof(A) * ];//申请了3个A的内存 A* pc = new(buf)A();//运用申请好的buf的内存,在buf上赋值
上面的new(buf)A();就是placement new.
编译器遇到上面代码会翻译成
A * pc;
try {
void* men = operator new(sizeof(A), buf); //借用内存
pc = static_cast<A*>(mem);//安全转换
pc->A::A();//构造函数
}
catch (std::bad_alloc){
//若失败 不执行构造函数
}
以上就是三种C++申请内存工具的介绍
参考侯捷<<C++内存管理>>
C++内存管理-new,delete,new[],placement new的简单使用的更多相关文章
- 内存管理——new delete expression
C++申请释放内存的方法与详情表 调用情况 1.new expression new表达式在申请内存过程中都发生了什么? 编译器将new这个分解为下面的主要3步代码,①首先调用operator new ...
- Java复习2.程序内存管理
前言: 国庆节的第三天,大家都回家了,一个人在宿舍好无聊.不过这年头与其说是出去玩不如是说出去挤,所以在学校里还是清闲的好.找工作不用担心了,到时候看着你们慢慢忙:插个话题,大学都没有恋爱过,总之各种 ...
- C/C++(C++内存管理,内联函数,类型转换,命名空间,string类)
---恢复内容开始--- 内存管理 new/delete C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请 ...
- 【UE4 C++】UObject 创建、销毁、内存管理
UObject 的创建 NewObject 模板类 本例使用 UE 4.26,只剩下 NewObject 用来创建 UObject,提供两个带不同可选参数构造函数的模板类 Outer 表示这个对象的外 ...
- iOS 非ARC基本内存管理系列 -手把手教你ARC——iOS/Mac开发ARC入门和使用(转)
手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objective-c 本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流 ...
- Delphi中ARC内存管理的方向
随着即将发布的10.3版本,RAD Studio R&D和PM团队正在制作Delphi在内存管理方面的新方向. 几年前,当Embarcadero开始为Windows以外的平台构建新的Delph ...
- iOS 内存管理的一点小问题
现在大家的项目应该基本都是ARC了,如果还是MRC的话,赶紧转换到ARC吧!最近被临时拉过去开发iPad,由于项目原因,还是使用的MRC.今天在调部分界面的时候,发现一段代码,我怎么看都怎么觉得怪怪的 ...
- Golang内存管理
Golang 内存管理 原文链接[http://legendtkl.com/2017/04/02/golang-alloc/] Golang 的内存管理基于 tcmalloc,可以说起点挺高的.但是 ...
- BEP 7:CUDA外部内存管理插件(下)
BEP 7:CUDA外部内存管理插件(下) Numba依赖 向库中添加EMM插件的实现自然会使Numba成为库的依赖项,而以前可能没有.为了使依赖关系可选,如果需要的话,可以有条件地实例化并注册EMM ...
随机推荐
- 第四篇——Struts2的引入多个配置文件
引入多个配置文件 在Struts2配置文件中使用include可引入多个配置文件. 项目实例 1.项目结构 2.pom.xml <project xmlns="http://maven ...
- byte[] 解析、转码二三事
1.先从byte 说起, byte 范围为 0~255 的整数,这个区间是在 int 范围中,所以 当byte 转为 int 时,则为小范围转大范围,隐式转换可以直接转换,反过来就是显式转换 需要Co ...
- 【Spark-core学习之四】 Spark任务提交
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...
- C#对象序列化成XML,以及自定义标签名
C#对象序列化操作: public class XMLHelper { /// <summary> /// 对象序列化成 XML String /// </summary> p ...
- ajax return 的问题
平时都是在AJAX里执行逻辑,实然想到能不能return返回数据呢? ajax 是异步请求,return拿值得时候 ajax并没有取到值,所以是undefind. 需要把ajax的请求方式改为同步 v ...
- Html table、thead、tr、th、td 标签
Html table.thead.tr.th.td 标签 案例一 <!-- table 表格标签,配置表格使用.border="1" 添加表格框架 --> <ta ...
- 时间序列数据库调研之InfluxDB
基于 Go 语言开发,社区非常活跃,项目更新速度很快,日新月异,关注度高 测试版本 1.0.0_beta2-1 安装部署 wget https://dl.influxdata.com/influxdb ...
- JNI与底层调用
交叉编译 在一个平台下,编译出另一个平台能够执行的二进制的代码 平台:windows,mac os,linux 处理器:x86,arm,mips 交叉编译的原理 源代码->编译->链接-& ...
- 剑指offer(7)斐波那契数列
题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项. n<=39 题目分析 我们都知道斐波那契可以用递归,但是递归重复计算的部分太多了(虽然可以通过),但是这 ...
- 改写element-ui中的日期组件
如果你想实现一个自定义的日期组件规则如下:日期组件未点开前左右两边有前一天后一天控制箭头,且前一天后一天有数据时才显示箭头,没有数据时,快速切换箭头隐藏.当日期组件点开后,有数据的天为可点击状态,无数 ...