技术在于交流、沟通,本文为博主原创文章转载请注明出处并保持作品的完整性

首先,我们先看一下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的简单使用的更多相关文章

  1. 内存管理——new delete expression

    C++申请释放内存的方法与详情表 调用情况 1.new expression new表达式在申请内存过程中都发生了什么? 编译器将new这个分解为下面的主要3步代码,①首先调用operator new ...

  2. Java复习2.程序内存管理

    前言: 国庆节的第三天,大家都回家了,一个人在宿舍好无聊.不过这年头与其说是出去玩不如是说出去挤,所以在学校里还是清闲的好.找工作不用担心了,到时候看着你们慢慢忙:插个话题,大学都没有恋爱过,总之各种 ...

  3. C/C++(C++内存管理,内联函数,类型转换,命名空间,string类)

    ---恢复内容开始--- 内存管理 new/delete C语言中提供了 malloc 和 free 两个系统函数,#include "stdlib.h"库函数,完成对堆内存的申请 ...

  4. 【UE4 C++】UObject 创建、销毁、内存管理

    UObject 的创建 NewObject 模板类 本例使用 UE 4.26,只剩下 NewObject 用来创建 UObject,提供两个带不同可选参数构造函数的模板类 Outer 表示这个对象的外 ...

  5. iOS 非ARC基本内存管理系列 -手把手教你ARC——iOS/Mac开发ARC入门和使用(转)

    手把手教你ARC——iOS/Mac开发ARC入门和使用 Revolution of Objective-c 本文部分实例取自iOS 5 Toturail一书中关于ARC的教程和公开内容,仅用于技术交流 ...

  6. Delphi中ARC内存管理的方向

    随着即将发布的10.3版本,RAD Studio R&D和PM团队正在制作Delphi在内存管理方面的新方向. 几年前,当Embarcadero开始为Windows以外的平台构建新的Delph ...

  7. iOS 内存管理的一点小问题

    现在大家的项目应该基本都是ARC了,如果还是MRC的话,赶紧转换到ARC吧!最近被临时拉过去开发iPad,由于项目原因,还是使用的MRC.今天在调部分界面的时候,发现一段代码,我怎么看都怎么觉得怪怪的 ...

  8. Golang内存管理

    Golang 内存管理 原文链接[http://legendtkl.com/2017/04/02/golang-alloc/] Golang 的内存管理基于 tcmalloc,可以说起点挺高的.但是 ...

  9. BEP 7:CUDA外部内存管理插件(下)

    BEP 7:CUDA外部内存管理插件(下) Numba依赖 向库中添加EMM插件的实现自然会使Numba成为库的依赖项,而以前可能没有.为了使依赖关系可选,如果需要的话,可以有条件地实例化并注册EMM ...

随机推荐

  1. MongoSpark 28799错误

    Exception : . The full response is { , "codeName" : "Location28799" } at com.mon ...

  2. Vim Tricks

    Vim Tricks operations replace :$s/from/to/g 全文替换 :10,20s/from/to/g 从第10行开始,替换至第20行 :10,20s/from/to/g ...

  3. docker原理与上帝进程

    做个笔记, 先水一会. 虚拟机指的是: 在软件的层面上通过模拟硬件进行的输入输出. docker原理:docker就是一个linux系统的进程, 它通过 Linux 的 namespaces 对不同的 ...

  4. mongodb集群配置及备份恢复

    Mongodb安装: 编辑/etc/yum.repos.d/mongodb.repo,添加以下: [MongoDB] name=MongoDB Repository baseurl=https://r ...

  5. hdu 5382 GCD?LCM! - 莫比乌斯反演

    题目传送门 传送门I 传送门II 题目大意 设$F(n) = \sum_{i = 1}^{n}\sum_{j = 1}^{n}\left [ [i, j] + (i, j) \geqslant n \ ...

  6. topcoder srm 585 div1

    problem1 link 最优的策略就是从最低下一层开始,每两层的三个节点的子树都可以用一次遍历覆盖. problem2 link 从大到小依次放置每一种数字,并记录已经放置的数字一共有多少个$m$ ...

  7. 【Visual Studio 扩展工具】使用ComponentOne中的GroupDefinition和SortDefinition属性保存和还原布局

    概述 在此前的ComponentOne中,我们为C1FlexGrid(最快,最灵活的.Net数据网格控件)添加了一个非常强大的动态分组功能,这篇技术博客<将动态分组添加到.NET表格控件Flex ...

  8. NodeJS:(一)特性&环境&测试

    特性: ①非阻塞I/O,事件驱动,单线程 非阻塞I/O:进程不等I/O完成(阻塞是等I/O完成后才进行下一步) 事件驱动:异步操作结束后通知 ②优点 前端职责范围变大,统一开发体验 处理高并发(单位时 ...

  9. postman(五):在不同接口之间传递数据

    为了更灵活地构造请求以及处理响应数据,postman提供了Pre-request-Script和Tests,在这两个标签中可以编写js代码辅助测试.之前学习了在发送请求的Tests标签如何添加断言以及 ...

  10. arch Linux(二)

    配置你的基本系统 下列是基于该视频4:40s的流水- 切换到普通用户: [root@eric-laptop ~]# su eric 查看系统信息: [eric@eric-laptop root]$ n ...