如何实现一个malloc?

malloc_tutorial.pdf

————————————————————————————————————

我们知道,使用malloc/calloc等分配内存的函数时,一定要检查其返回值是否为“空指针”(亦即是检查分配内存的操作是否成功),这是良好的编程习惯,也是编写可靠程序所必需的。但是,如果你简单的把这一招应用到new上,那就不一定正确了。

C++里,如果new分配内存失败,默认是抛出异常的如果你想检查new是否成功,应该捕捉异常。

    try{
int* p = new int[SIZE];
//其他代码
}catch( const bad_alloc& e ){
return -;
}

当然,标准的C++亦提供了一个方法来抑制new抛出异常,而返回空指针:

    int* p = new (std::nothrow) int; //这样,如果new失败了,就不会抛出异常,而是返回空指针
if( p== )//如此这般,这个判断就有意义了
return -;
//其他代码

——————————————————————以上都是无用之谈

new的语法格式:new 数据类型(初始化参数列表);

关于new后加()与不加()的区别:

  在用new建立一个类的对象时,若存在用户定义的默认构造函数,则new T和new T()两写法效果相同,都会调用此默认构造函数;若未定义,new T会调用系统默认构造函数,new T()除了调用系统默认构造函数,还会给基本数据类型和指针类型的成员用0赋值,且该过程是递归的。即若该对象的某个成员对象未定义默认构造函数,那么该成员对象的基本数据类型和指针类型的成员同样会被以0赋值。

故用new的时候请加上()。

运算符delete用来删除由new建立的对象,释放指针所指向的内存空间。

——————————————————————

关于new数组类型的对象:

语法格式: new 类型名 [数组长度];

delete[] 指针名;

如int* p = new int[10]();

delete[] p;

——————————————————————

多维数组:

语法格式: new 类型名T[第一维长度][第二维长度]...;

其中第1维长度是任何结果为正整数的表达式,其余必须是正整数的常量表达式(因为是常量,故不能直接分配两维都不固定的数组)。

若内存申请成功,返回指向新分配内存的首地址的指针,但不是T类型指针,而是指向T类型数组的指针,数组元素的个数为除第一维外各维下标表达式的乘积。

如int (*p)[25][10];          //请把p抽出来看,p的类型为 int* [25][10]

p = new int[10][25][10];

则指针p即可以作为指针用,也可以当一个三维数组名用。

再举例如下:

int *p = new int[];          //返回一个指向int的指针int*.

int (*p)[] = new int[][];    //new了一个二维数组,返回一个指向int[10]这种一维数组的指针int(*)[10].

int (*p)[][] = new int[][][]; //new了一个三维数组,返回一个指向二维数组int[2][10]这种类型的指针int (*)[2][10].

注意:new int[0][10]和new int[][10]都是无分配内存。

那么如果第二维都不确定怎么办呢?

    int **a = new int*[n];
for(int i = ; i < n; i++)
a[i] = new int[n]();
//分配n*n的数组,还可以a[i] = new int[i]();有点java的味道...
  for(int i = ; i < n; i++)
    delete[] a[i];
  delete[] a;
当char * a=new char[10]后,程序结束需要delete [] a请问为什么不需要写delete [10] a ,即计算机是怎么知道是数组大小的?
参考以下链接:
https://blog.csdn.net/hazir/article/details/21413833

How do compilers use “over-allocation” to remember the number of elements in an allocated array?

// Original code: Fred* p = new Fred[n];
char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
Fred* p = (Fred*) (tmp + WORDSIZE);
*(size_t*)tmp = n;
size_t i;
try {
for (i = ; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != )
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] ((char*)p - WORDSIZE);
throw;
}
// Original code: delete[] p;
size_t n = * (size_t*) ((char*)p - WORDSIZE);
while (n-- != )
(p + n)->~Fred();
operator delete[] ((char*)p - WORDSIZE);

How do compilers use an “associative array” to remember the number of elements in an allocated array?

// Original code: Fred* p = new Fred[n];
Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
size_t i;
try {
for (i = ; i < n; ++i)
new(p + i) Fred(); // Placement new
}
catch (...) {
while (i-- != )
(p + i)->~Fred(); // Explicit call to the destructor
operator delete[] (p);
throw;
}
arrayLengthAssociation.insert(p, n);
// Original code: delete[] p;
size_t n = arrayLengthAssociation.lookup(p);
while (n-- != )
(p + n)->~Fred();
operator delete[] (p);

参考链接:https://isocpp.org/wiki/faq/compiler-dependencies#num-elems-in-new-array-overalloc

malloc/free与new/delete的策略类似,new/delete是malloc/free的上层

https://stackoverflow.com/questions/197675/how-does-delete-know-the-size-of-the-operand-array

====================================================================

隐式空闲链表(任何操作的开销都与堆中已分配块和未分配块的总数呈线性关系)

带边界标记的合并(块分配与堆块的总数呈线性关系,合并空闲块常数时间)

显式空闲链表(分配时间从块总数减少为空闲块数量的线性时间,释放时间取决于空闲链表块的排序策略,LIFO则常数时间释放,按地址顺序排序则线性时间释放,如果采用了边界标记,合并时间常数)

分离的空闲链表:简单分离存储 / 分离适配 / 伙伴系统

C++中关于new及动态内存分配的思考的更多相关文章

  1. 第10课 C++中的动态内存分配

    C++中的动态内存分配 C语言是通过库函数来完成动态内存分配的,而C++是通过关键字从语言层面支持的. C语言中的malloc是基于字节来进行内存申请的,C++中是基于类型来进行的. delete加上 ...

  2. Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF

    1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是: BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...

  3. c++动态内存分配需要注意的地方,可以不用尽量不用

    在实际开发中,需要动态分配内存的场景极少,string和vector已经足够方便,如果不是非用不可的情况,采用动态分配内存就是给自己挖坑. 如果应用开发中一定要用动态内存分配技术,建议把它封装在类中, ...

  4. rt-thread中动态内存分配之小内存管理模块方法的一点理解

    @2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...

  5. C++解析(25):关于动态内存分配、虚函数和继承中强制类型转换的疑问

    0.目录 1.动态内存分配 1.1 new和malloc的区别 1.2 delete和free的区别 2.虚函数 2.1 构造函数与析构函数是否可以成为虚函数? 2.2 构造函数与析构函数是否可以发生 ...

  6. C++_类和动态内存分配3-构造函数中使用new的注意事项

    如果在构造函数中使用new来初始化对象的指针成员时必须特别小心. 1 如果在构造函数中使用new来初始化指针成员,则应在析构函数中使用delete. 2 new和delete必须相互兼容.new对应于 ...

  7. C语言中动态内存分配的本质是什么?

    摘要:C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配. 本文分享自华为云社区<[云驻共创]C语言中动态内存分配的本质>,作者: G ...

  8. C++指针和动态内存分配

    指针和动态内存分配 数组与指针 数组 数组名是一个指针常量. 数组名传递数据时,传递的是地址. 数组作为函数参数时不指定第一维大小. 对象数组 A a[2] = {A(1,2)}; 执行时先调用有参数 ...

  9. SQLite剖析之动态内存分配

    SQLite通过动态内存分配来获取各种对象(例如数据库连接和SQL预处理语句)所需内存.建立数据库文件的内存Cache.保存查询结果. 1.特性    SQLite内核和它的内存分配子系统提供以下特性 ...

随机推荐

  1. NUnit基本使用方法

    通常的单元测试框架都以他们支持的语言的开头字母加上Unit作为名字,他们统称为xUnit框架.C++的叫做CppUnit,Java的叫做JUnit,.Net的叫做NUnit.当然不是所有的都这么命名, ...

  2. pytest使用笔记(三)——pytest+allure+jenkins配置使用

    按照pytest使用笔记(二)把pytest+allure配置好后,现在在jenkins配置好,先实现手动构建(立个小目标) 一,安装jenkins插件 首页->系统管理->插件管理,从“ ...

  3. WebGL树形结构的模型渲染流程

    今天和大家分享的是webgl渲染树形结构的流程.用过threejs,babylonjs的同学都知道,一个大模型都是由n个子模型拼装而成的,那么如何依次渲染子模型,以及渲染每个子模型在原生webgl中的 ...

  4. discuz修改附件出售用其他积分,与帖子不一样

    现实中我遇到了这种情况,一个资源可以用两种积分购买,于是我决定用售卖贴和出售附件的方式,附件内容与贴内隐藏内容是一样的,但目前discuz的出售主题和附件使用的是同一种积分,有了此修改 1.首先是显示 ...

  5. “错误: 编码GBK的不可映射字符” 的解决方案

    命令行下,用javac命令编译java程序时,如果文档的编码为“utf-8”,并且含有中文字符时,会出现乱码现象,编译通过不了.如图: 解决方案:编译时指定编码方式,防止乱码.如下:

  6. Centos7.2部署saltstack

    原文发表于cu:2016-06-23 参考文档: Saltstack安装文档:https://repo.saltstack.com/#rhel saltstack的安装与简单配置,应用. 一.环境 S ...

  7. 【第七章】MySQL数据库备份-物理备份

    一.数据库备份 备份的目的: 备份: 能够防止由于机械故障以及人为误操作带来的数据丢失,例如将数据库文件保存在了其它地方. 冗余: 数据有多份冗余,但不等备份,只能防止机械故障还来的数据丢失,例如主备 ...

  8. java处理大文本2G以上

    面试中经常碰到类似问题,问题的关键我觉得是用设置一个缓冲区 还有一个思路 是通过Linux split 命令将文件直接切割成小文件,再进行处理再汇总. 或者jdk7提供的 forkjoin 框架,利用 ...

  9. 团队项目NABCD

    团队成员及项目简介 团队名:伍陸柒 团队成员: 李  俏(20132912 信1301-2) 郝  颖(20132919 信1301-2)http://www.cnblogs.com/haoying1 ...

  10. Android开发第二阶段(3)

    今天:对闹钟代码的按钮事件进行了添加和修改.对监听器的相关应用也有了进一步的了解和深入. 明天:对主界面的代码的优化比如对按钮位置的调节等细节处理.