C++中关于new及内存地址的思考
————————————————————————————————————
我们知道,使用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及内存地址的思考的更多相关文章
- android 绑定spinner键值对显示内存地址的问题
初学android,估计是.net学傻了,觉得android好麻烦. 绑定下拉菜单Spinner键值对. 参照这篇文章,地址:http://blog.csdn.net/shouliang52000/a ...
- 【java多线程系列】java中的volatile的内存语义
在java的多线程编程中,synchronized和volatile都扮演着重要的 角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,可见性指的是当一 ...
- golang for 循环变量取内存地址
前几天提交的代码进行测试的时候发现变量无法赋值,原始代码如下: for _, asset := range dspInfo.native.Assets { var resAsset protocol. ...
- VC++中的类的内存分布(上)(通过强制转换,观察地址,以及地址里的值来判断)
0.序 目前正在学习C++中,对于C++的类及其类的实现原理也挺感兴趣.于是打算通过观察类在内存中的分布更好地理解类的实现.因为其实类的分布是由编译器决定的,而本次试验使用的编译器为VS2015 RC ...
- macOS下利用dSYM文件将crash文件中的内存地址转换为可读符号
一.使用流程 Windows下的程序运行崩溃时,往往可以利用pdb文件快速解析出程序崩溃的具体位置,甚至可以对应到源代码的具体行数.macOS下的symbolicatecrash也具备相应的功能.对应 ...
- Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器
Android For JNI(二)--C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器 当我们把Hello World写完之后,我们就可以迈入C的大门了,今天就来讲讲基本的一些数据类型 ...
- python中的函数对象的内存地址是多少
今天和同学讨论一个问题,发现了函数的内存地址和我想象的不一样. 我以为同一个函数,假如给的参数不一样,那么这两个函数的id就不一样. 然后经过实验,发现python为了便于管理函数,所有的函数都放在同 ...
- Window中的内存地址(小知识)
现在的编辑器大部分工作都是内存管理托管型,所以很少直接对Window的内存地址直接管理了. Window中的内存地址主要是以16进制数字体现的,当操作系统为32位时,那么每个内存地址为2的32次方,也 ...
- 数组中hashCode就是内存地址,以及汉字幻化为16进制或10进制
int[] arr4={1,2,3,4,5}; System.out.println("arr4: "+arr4); System.out.println("arr4.h ...
随机推荐
- JavaEE基础(一)
1.计算机基础知识(计算机概述) A:什么是计算机?计算机在生活中的应用举例 计算机(Computer)全称:电子计算机,俗称电脑.是一种能够按照程序运行,自动.高速处理海量数据的现代化智能电子设备. ...
- php变量内存完全释放
<?php echo memory_get_usage().PHP_EOL;$a = 1;$b = $a;$a = null;$b = null;unset($a);unset($b);echo ...
- JavaScript push()和splice()方法
JavaScript push() 方法 定义和用法 push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度. 语法 arrayObject.push(newelement1,newele ...
- 使用Decision Tree对MNIST数据集进行实验
使用的Decision Tree中,对MNIST中的灰度值进行了0/1处理,方便来进行分类和计算熵. 使用较少的测试数据测试了在对灰度值进行多分类的情况下,分类结果的正确率如何.实验结果如下. #Te ...
- hdu4727 The Number Off of FFF
理解错题意,wa了几次. 我一开始的理解忽略了实际背景,认为错报是绝对的,不依赖于其左边的人. 而实际上某士兵报数的对错取决且仅取决于他所报的数与其左邻所报的数. 所以假设第一个人没有报错,则其后必有 ...
- HDU(3555),数位DP
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others ...
- 使用UML进行项目开发
一.概述 本文主要论述的内容是如何使用UML来指导(辅助)项目设计.在此篇文章中,假设读者对UML已经有了概念上的认识,对UML中出现的名词都能很好的理解. UML的目标是以面向对象图的方式来描述任何 ...
- MUI 授权
步骤1.打开 manifest.json 视图 在permissions 下添加 "Payment": {"description": "支付&q ...
- white的配置使用
初次使用White来自动化测试10个9相加1.新建Visual C#->测试->单元测试项目2.在资源视图->引用,右键,添加引用,添加White的两个.dll文件3.在工程中添加命 ...
- acdream1197 Points In Cuboid(hash树状数组)
题目链接:http://acdream.info/problem?pid=1197 题意:给出三维空间n个点,m个查询,每次查询某个立方体内的点的个数. 思路:按照一维排序,根据查询插入,其他两位用二 ...