C++动态内存分配(new/new[]和delete/delete[])详解分享

—-想了解C++动态内存分配(new/new[]和delete/delete[])详解分享的全部内容且更多的C语言教程关注<计算机技术网(www.ctvol.com)!!>

C++动态内存分配(new/new[]和delete/delete[])详解

为了解决这个普通的编程问题,在运行时能创建和销毁对象是基本的要求。当然,C已提供了动态内存分配函数malloc( )和free( ),以及malloc( )的变种(realloc:改变分配内存的大小,calloc:指针指向内存前初始化),这些函数在运行时从堆中(也称自由内存)分配存储单元,但是运用这些库函数需要计算需要开辟内存的大小,容易出现错误。

     那么通常我们在C语言中我们开辟内存的方式如下:

  (void*)malloc(sizeof(void)); 

然而,在C+ +中这些函数不能很好地运行。构造函数不允许通过向对象传递内存地址来初始化它。如果那么做了,我们可能

当然,即使我们把每件事都做得很正确,修改我们的程序的人也容易犯同样的错误。不正确的初始化是编程出错的主要原因,所以在堆上创建对象时,确保构造函数调用是特别重要的。

C+ +是如何保证正确的初始化和清理并允许我们在堆上动态创建对象的呢?

    答案是使动态对象创建成为语言的核心。malloc( )和free( )是库函数,因此不在编译器控制范围之内。如果我们有一个能完成动态内存分配及初始化工作的运算符和另一个能完成清理及释放内存工作的运算符,编译器就可以保证所有对象的构造函数和析构函数都会被调用。

    若使用原始的动态内存开辟方式就会显得很繁琐,具体代码如下:

  #include<cstdlib>   #include<cstring>   #include<iostream>   using namespace std;   class Obj   {    int i,j,k;    enum {sz=100};    char buf[sz];   public:     void initialize()     {       cout<<"initialize"<<endl;       i=k=j=0;       memset(buf,0,sz);     }     void destroy() const     {      cout<<"destroying Obj"<<endl;     }   };   int main()   {     Obj* obj=(Obj*)malloc(sizeof(Obj));      if(obj!=0)     obj->initialize();     obj->destroy();     free(obj);    return 0;   }

     在上面这行代码中,我们可以看到使用malloc( )为对象分配内存:obj* Obj = (obj*)malloc(sizeof(obj)) ;
这里用户必须决定对象的长度(这也是程序出错原因之一)。因为它是一块内存而不是一个对象,所以malloc( )返回一个void*.C++不允许将一个void* 赋予任何指针,所以必须映射。因为malloc( )可能找不到可分配的内存(在这种情况下它返回 0),所以必须检查返回的指针以确信内存分配成功。

但最坏的是:Obj->initialize( ) ;用户在使用对象之前必须记住对它初始化。注意构造函数没有被使用,因为构造函数不能被显式地调用—而是当对象创建时由编译器调用。这里的问题是现在用户可能在使用对象时忘记执行初始化,因此这也是引入程序缺陷的主要来源。许多程序设计者发现 C的动态内存分配函数太复杂,令人混淆。所以, C程序设计者常常在静态内存区域使用虚拟内存机制分配很大的变量数组以避免使用动态内存分配。因为C++能让一般的程序员安全使用库函数而不费力,所以应当避免使用 C的动态内存方法。C++中的解决方案是把创建一个对象所需的所有动作都结合在一个称为new的运算符里。当用new(new的表达式)创建一个对象时,它就在堆里为对象分配内存并为这块内存调用构造函数。

    因此,如果我们写出下面的表达式foo *fp = new foo(1,2) ; 在运行时等价于调用malloc(sizeof(foo)),并使用(1,2)作为参数表来为

foo调用构造函数,返回值作为this指针的结果地址。在该指针被赋给 fp之前,它是不定的、未初始化的对象— 在这之前我们甚至不能触及它。它自动地被赋予正确的 foo类型,所以不必进行映射。缺省的new还检查以确信在传递地址给构造函数之前内存分配是成功的,所以我们不必显式地确定调用是否成功。在本章后面,我们将会发现,如果没有可供分配的内存会发生什么事情。我们可以为类使用任何可用的构造函数而写一个 ne w表达式。如果构造函数没有参数,可以写没有构造函数参数表的new表达式:

foo *fp = new foo ;我们已经注意到了,在堆里创建对象的过程变得简单了—只是一个简单的表达式 ,它带有内置的长度计算、类型转换和安全检查。这样在堆里创建一个对象和在栈里创建一个对象一样容易。

new表达式的反面是delete表达式。delete表达式首先调用析构函数,然后释放内存(经常是调用free( ))。正如new表达式返回一个指向对象的指针一样,delete表达式需要一个对象的地址。delete fp ;上面的表达式清除了早先创建的动态分配的对象foo。delete只用于删除由new创建的对象。如果用malloc( )(或calloc( )或realloc( ))创建一个对象,然后用delete删除它,这个行为是未定义的。因为大多数缺省的new和delete实现机制都使

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/488054.html

(0)
上一篇 2020年11月12日
下一篇 2020年11月12日

精彩推荐