C++中关于new及内存地址的思考

Posted Dirge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++中关于new及内存地址的思考相关的知识,希望对你有一定的参考价值。

OJ题刷多了,每次都是直接分配内存,那么,你还记得怎么动态分配内存吗?

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

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

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

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

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

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

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

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[10];          //返回一个指向int的指针int*.

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

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

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

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

    int **a = new int*[n];
    for(int i = 0; i < n; i++)
        a[i] = new int[n]();
//分配n*n的数组,还可以a[i] = new int[i]();有点java的味道...
  for(int i = 0; i < n; i++)
    delete[] a[i];
  delete[] a;

关于delete的思考:摘自百度知道

当char * a=new char[10]后,程序结束需要delete [] a请问为什么不需要写delete [10] a ,即计算机是怎么知道是数组大小的?
————————————————————————————————————————————————————————————————————————————————
关于new和delete,似乎总是有说不完的话题。

首先,char * a=new char[10]之后,一般来说系统当然知道并且会记录你所申请的内存大小。反过来试想一下,要是系统不知道你申请了多少内存,而是在你delete[]的时候傻乎乎的等你告诉它,万一你一个不小心传个1000000000进去,那还得了?

实际上,如果仅仅是为了回收内存,C++没必要设计一个delete[],delete就够了。但delete不光是回收内存,在这之前,它还要负责调用析构函数。这里因为是char类型,所以没析构,根据你使用的编译器,说不定不管你用delete和delete[],程序都没问题,不会崩溃也不会内存泄露(相信我,在VS2005上就是这样)。
不过,如果是一个class(或者是带析构的struct),区别就来了。delete告诉编译器你释放的是单个对象,所以只会在你给的对象地址上调用析构;delete[]则告诉编译器,你要释放一个对象数组,那么就会对每一个对象调用析构。
“等一下”,你会说,“delete[]的时候我没有写数组大小,系统怎么知道有多少个对象?”嗯,系统当然知道,就像它知道你申请了多少内存一样。因为早在你new[](这个时候你总得写清楚你要多少个对象)的时候,系统就悄悄记下来了。哦,不,应该说,这些事是你亲爱的C++编译器替你做的。不同的编译器,记录的方式可能不同。再次用可爱的VS2005举例,如果你用了new[]生成一个对象数组(要带析构的),本来可能只需要100字节,但是实际上会申请104个字节,多出来的4个字节,就是用来保存数组长度的。而用new的话,就没这些东西。这个时候,new[]、delete[]就必须配对了,这样编译器才知道,它要先去找到数组长度,然后一个一个对象的析构。

以上是关于C++中关于new及内存地址的思考的主要内容,如果未能解决你的问题,请参考以下文章

new delete和mallocfree的解析及区别

C++内存四大区域

C++内存泄漏的思考和总结

C++内存泄漏的思考和总结

C++内存泄漏的思考和总结

C++初阶:内存管理C/C++内存分布及管理方式 | new/delete实现原理及operator new和operator delete函数