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 ...
随机推荐
- Composer使用中常见的问题
安装了Composer后,运行 composer --version ,查看Composer的版本号.如果出现下面的提示,那么软件安装成功. Composer version 1.2.0 2016-0 ...
- Codeforces 743D:Chloe and pleasant prizes(树形DP)
http://codeforces.com/problemset/problem/743/D 题意:求最大两个的不相交子树的点权和,如果没有两个不相交子树,那么输出Impossible. 思路:之前好 ...
- postgresql压力测试工具用法以及参数解读
pgbench是PostgreSQL自带的一个数据库压力测试工具, 支持TPC-B测试模型, 或自定义测试模型. 自定义测试模型支持元命令, 调用shell脚本, 设置随机数, 变量等等. 支持3种异 ...
- [UML]转:浅谈UML的概念和模型之UML九种图
转自:http://blog.csdn.net/jiuqiyuliang/article/details/8552956 目录: UML的视图 UML的九种图 UML中类间的关系 上文我们介绍了,UM ...
- python :生产者和消费者模型 即简单的协程
def consumer(name): print('%s开始准备吃包子了' %name) while True: baozi=yield print('[%s]包子来了,被[%s]吃了' %(bao ...
- python-day 1
学python--脚本语言 为了更好的以后,为了更好的自己,加油!!! 1.安装虚拟机如果遇到这样的错误:此主机支持intel vt-x 处于禁用状态错误 解决方法: 进入BIOS后,找到“Syste ...
- [转]iOS学习之UINavigationController详解与使用(一)添加UIBarButtonItem
转载地址:http://blog.csdn.net/totogo2010/article/details/7681879 1.UINavigationController导航控制器如何使用 UINav ...
- js格式化日期 年月日
/** * 格式化日期 * @param value * @param row ...
- 20151124001 关闭C#主窗体弹出是否关闭对话框
关闭C#主窗体弹出是否关闭对话框 private void Frm_Main_FormClosing(object sender, FormClosingEventArgs e) { ...
- 20150916_001 vba 基础
一.什么是“宏”.“宏”有什么用 关于“宏”的详细定义,可以参考百度百科的解释(点击查看).我给它一个简单的或许不太严谨的定义: 宏的通俗定义:宏是被某些软件所能识别.理解并执行的特定代码/脚本. 宏 ...