如何实现一个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. android 绑定spinner键值对显示内存地址的问题

    初学android,估计是.net学傻了,觉得android好麻烦. 绑定下拉菜单Spinner键值对. 参照这篇文章,地址:http://blog.csdn.net/shouliang52000/a ...

  2. 【java多线程系列】java中的volatile的内存语义

    在java的多线程编程中,synchronized和volatile都扮演着重要的 角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,可见性指的是当一 ...

  3. golang for 循环变量取内存地址

    前几天提交的代码进行测试的时候发现变量无法赋值,原始代码如下: for _, asset := range dspInfo.native.Assets { var resAsset protocol. ...

  4. VC++中的类的内存分布(上)(通过强制转换,观察地址,以及地址里的值来判断)

    0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC ...

  5. macOS下利用dSYM文件将crash文件中的内存地址转换为可读符号

    一.使用流程 Windows下的程序运行崩溃时,往往可以利用pdb文件快速解析出程序崩溃的具体位置,甚至可以对应到源代码的具体行数.macOS下的symbolicatecrash也具备相应的功能.对应 ...

  6. Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器

    Android For JNI(二)--C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器 当我们把Hello World写完之后,我们就可以迈入C的大门了,今天就来讲讲基本的一些数据类型 ...

  7. python中的函数对象的内存地址是多少

    今天和同学讨论一个问题,发现了函数的内存地址和我想象的不一样. 我以为同一个函数,假如给的参数不一样,那么这两个函数的id就不一样. 然后经过实验,发现python为了便于管理函数,所有的函数都放在同 ...

  8. Window中的内存地址(小知识)

    现在的编辑器大部分工作都是内存管理托管型,所以很少直接对Window的内存地址直接管理了. Window中的内存地址主要是以16进制数字体现的,当操作系统为32位时,那么每个内存地址为2的32次方,也 ...

  9. 数组中hashCode就是内存地址,以及汉字幻化为16进制或10进制

    int[] arr4={1,2,3,4,5}; System.out.println("arr4: "+arr4); System.out.println("arr4.h ...

随机推荐

  1. ecshop简单三部实现导航分类二级菜单

    1.在page_header.lbi对应的位置(你想显示导航的位置)插入 (注意下面的"themes/模板名称/util.php"中的"模板名称"改成你模板文件 ...

  2. 工具类 dp转px 获取图片实际尺寸 获取屏幕尺寸

    dp转px public class Dp2pxUtils { public static int Dp2Px(Context context, float dp) { final float sca ...

  3. [Ogre][地形]OgreTerrain的实现原理分析

    转自:http://www.xuebuyuan.com/1482609.html 一.世界地图 将整个世界切分成多个Tile,每个Tile大小相同,用二维坐标形式索引起来,如图: 中心点(0,0)位置 ...

  4. 每日一九度之 题目1023:EXCEL排序

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:18804 解决:4240 题目描述:     Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能.     对每个测试用例 ...

  5. Python 中translate()与replace()区别

    translate函数和replace函数一样,用于替换字符串中的某个部分,但是和replace不同,translate只处理单个字符,而且可以同时进行多个替换.在使用translate函数转换之前, ...

  6. 【转】西门子数控系统中MMC、PCU、NCU、CCU简略介绍

    转载地址:http://cyj221.blog.163.com/blog/static/34194117201093005526170/ 2010-10-30 01:06:09|  分类: 机械制造 ...

  7. hiho 第119周 最大权闭合子图

    描述 周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编 ...

  8. Codeforces Round #372 (Div. 2) B

    Description ZS the Coder loves to read the dictionary. He thinks that a word is nice if there exists ...

  9. 2016年11月14日 星期一 --出埃及记 Exodus 20:5

    2016年11月14日 星期一 --出埃及记 Exodus 20:5 You shall not bow down to them or worship them; for I, the LORD y ...

  10. mysq 安装时候进行生成数据库系统时候执行语句 ./scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql 时候报错

    我在安装数据库时候在系统进行生成数据库时候出现下面问题,就是在 scripts里面mysql_install_db没有执行权限, 进入到scripts目录下,执行chmod 777 mysql_ins ...