精华内容
下载资源
问答
  • 最近被问到了C++内存池的问题,其中不免涉及到在指定内存地址调用对象构造函数以及显示调用对象析构函数的情况。</p> C++中new的用法 new是C++中用于动态内存分配的运算符,在C语言中一般使用malloc函数。 ...

    C++中new的用法及显示调用析构函数
    <p>最近被问到了C++内存池的问题,其中不免涉及到在指定内存地址调用对象构造函数以及显示调用对象析构函数的情况。</p>
    

    C++中new的用法

    new是C++中用于动态内存分配的运算符,在C语言中一般使用malloc函数

    (1)plain new顾名思义就是普通的new,就是我们惯常使用的new。分配内存,调用构造函数,在C++中是这样定义的:

    1 void* operator new(std::size_t) throw(std::bad_alloc);
    2 void operator delete(void *) throw();

    plain new在分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,因此通过判断返回值是否为NULL是徒劳的。

    复制代码
     1 #include "stdafx.h"
     2 #include <iostream>
     3 using namespace std;
     4 char *GetMemory(unsigned long size)
     5 {
     6     char *p=new char[size];//分配失败,不是返回NULL
     7     return p;
     8 }
     9 
    10 int main()
    11 {
    12     try
    13     {
    14           char *p=GetMemory(10e11);// 分配失败抛出异常std::bad_alloc
    15           //...........
    16           if(!p)//徒劳
    17            cout<<"failure"<<endl;
    18           delete [] p;
    19     }
    20     catch(const std::bad_alloc &ex)
    21     {
    22           cout<<ex.what()<<endl;
    23     }
    24 
    25     return 0;
    26 }
    复制代码

     

    (2)nothrow new是不抛出异常的运算符new的形式。nothrow new在失败时,返回NULL。定义如下:

    1 void * operator new(std::size_t,const std::nothrow_t&) throw();
    2 void operator delete(void*) throw(); 
    复制代码
     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <new>
     4 using namespace std;
     5 char *GetMemory(unsigned long size)
     6 {
     7     char *p=new(nothrow) char[size];//分配失败,是返回NULL
     8     if(NULL==p)
     9           cout<<"alloc failure!"<<endl;
    10     return p;
    11 }
    12 
    13 int main()
    14 {
    15     try
    16     {
    17           char *p=GetMemory(10e11);
    18           //...........
    19           if(p==NULL)
    20                cout<<"failure"<<endl;
    21           delete [] p;
    22     }
    23     catch(const std::bad_alloc &ex)
    24     {
    25           cout<<ex.what()<<endl;
    26     }
    27     return 0;
    28 }
    复制代码

     

    (3)placement new意即“放置”,这种new允许在一块已经分配成功的内存上重新构造对象或对象数组。placement new不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数。定义如下:

    1 void* operator new(size_t,void*);
    2 void operator delete(void*,void*);

    palcement new的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组。placement new构造起来的对象或其数组,要显示的调用他们的析构函数来销毁,千万不要使用delete。

    复制代码
     1 #include "stdafx.h"
     2 #include <iostream>
     3 #include <new>
     4 using namespace std;
     5 class ADT
     6 {
     7     int i;
     8     int j;
     9 public:
    10     ADT()
    11     {
    12     }
    13     ~ADT()
    14     {
    15     }
    16 };
    17 
    18 int main()
    19 {
    20     char *p=new(nothrow) char[sizeof(ADT)+2];
    21     if(p==NULL)
    22           cout<<"failure"<<endl;
    23     ADT *q=new(p) ADT;  //placement new:不必担心失败
    24     // delete q;//错误!不能在此处调用delete q;
    25     q->ADT::~ADT();//显示调用析构函数
    26     delete []p;
    27     return 0;
    28 }
    复制代码

    使用placement new构造起来的对象或数组,要显式调用它们的析构函数来销毁(析构函数并不释放对象的内存),千万不要使用delete.这是因为placement new构造起来的对象或数组大小并不一定等于原来分配的内存大小,
    使用delete会造成内存泄漏或者之后释放内存时出现运行时错误。
     

    另:

    当使用new运算符定义一个多维数组变量或数组对象时,它产生一个指向数组第一个元素的指针,返回的类型保持了除最左边维数外的所有维数。例如:  

     int *p1 = new int[10];   

    返回的是一个指向int的指针int*  

    int (*p2)[10] = new int[2][10]; 

    new了一个二维数组, 去掉最左边那一维[2], 剩下int[10], 所以返回的是一个指向int[10]这种一维数组的指针int (*)[10].  

    int (*p3)[2][10] = new int[5][2][10];  new了一个三维数组, 去掉最左边那一维[5], 还有int[2][10], 所以返回的是一个指向二维数组int[2][10]这种类型的指针int (*)[2][10].     

    复制代码
    #include<iostream>
    

    #include <typeinfo>

    using namespace std;

    int main() {

    int *a = new int[34];

    int *b = new int[];

    int (*c)[2] = new

    int[34][2];

    int (*d)[2] = new int[][2];

    int (*e)[2][3] = new int[34][2][3];

    int (*f)[2][3] = new int[][2][3];

    a[0] = 1;

    b[0] = 1; //运行时错误,无分配的内存,b只起指针的作用,用来指向相应的数据

    c[
    0][0] = 1;

    d[0][0] = 1;//运行时错误,无分配的内存,d只起指针的作用,用来指向相应的数据

    e[
    0][0][0] = 1;

    f[0][0][0] = 1;//运行时错误,无分配的内存,f只起指针的作用,用来指向相应的数据

    cout
    <<typeid(a).name()<<endl;

    cout<<typeid(b).name()<<endl;

    cout<<typeid©.name()<<endl;

    cout<<typeid(d).name()<<endl;

    cout<<typeid(e).name()<<endl;

    cout<<typeid(f).name()<<endl;

    delete[] a; delete[] b; delete[] c;

    delete[] d; delete[] e; delete[] f;

    }

    输出结果:

    int *

    int *

    int (*)[2]

    int (*)[2]

    int (*)[2][3]

    int (*)[2][3]

    复制代码

    深入学习文献C++new用法深层剖析

     

    C++显示调用析构函数

    一、文章来由

    现在在写一个项目,需要用到多叉树存储结构,但是在某个时候,我需要销毁这棵树,这意味着如果我新建了一个树对象,我很可能在某处希望将这个对象的声明周期终结,自然会想到显示调用析构函数,但是就扯出来这么大个陷阱。

    二、原因

    在了解为什么不要轻易显示调用析构函数之前,先来看看预备知识。 
    为了理解这个问题,我们必须首先弄明白“堆”和“栈”的概念。

    1)堆区(heap) —— 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

    2)栈区(stack) —— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

    我们构造对象,往往都是在一段语句体中,比如函数,判断,循环,还有就直接被一对“{}”包含的语句体。这个对象在语句体中被创建,在语句体结束的时候被销毁。问题就在于,这样的对象在生命周期中是存在于栈上的。也就是说,如何管理,是系统完成而程序员不能控制的。所以,即使我们调用了析构,在对象生命周期结束后,系统仍然会再调用一次析构函数,将其在栈上销毁,实现真正的析构。

    所以,如果我们在析构函数中有清除堆数据的语句,调用两次意味着第二次会试图清理已经被清理过了的,根本不再存在的数据!这是件会导致运行时错误的问题,并且在编译的时候不会告诉你!

    三、显示调用带来的后果

    如果硬要显示调用析构函数,不是不可以,但是会有如下3条后果:

    1)显式调用的时候,析构函数相当于的一个普通的成员函数

    2)编译器隐式调用析构函数,如分配了对内存,显式调用析构的话引起重复释放堆内存的异常

    3)把一个对象看作占用了部分栈内存,占用了部分堆内存(如果申请了的话),这样便于理解这个问题,系统隐式调用析构函数的时候,会加入释放栈内存的动作(而堆内存则由用户手工的释放);用户显式调用析构函数的时候,只是单纯执行析构函数内的语句,不会释放栈内存,也不会摧毁对象

    用如下代码表示:

    例1:

    class aaa
    {
    public:
        aaa(){}
        ~aaa(){cout<<"deconstructor"<<endl; } //析构函数
        void disp(){cout<<"disp"<<endl;}
    private:
        char *p;
    };
    

    void main()
    {
    aaa a;
    a.~aaa();
    a.disp();
    }

     

    分析:

    这样的话,显式两次destructor,第一次析构相当于调用一个普通的成员函数,执行函数内语句,显示第二次析构是编译器隐式的调用,增加了释放栈内存的动作,这个类未申请堆内存,所以对象干净地摧毁了,显式+对象摧毁

    例2:

    class aaa
    {
    public:
        aaa(){p = new char[1024];} //申请堆内存
        ~aaa(){cout<<"deconstructor"<<endl; delete []p;}
        void disp(){cout<<"disp"<<endl;}
    private:
        char *p;
    };
    

    void main()
    {
    aaa a;
    a.~aaa();
    a.disp();
    }

    分析:

    这样的话,第一次显式调用析构函数,相当于调用一个普通成员函数,执行函数语句,释放了堆内存,但是并未释放栈内存,对象还存在(但已残缺,存在不安全因素);第二次调用析构函数,再次释放堆内存(此时报异常),然后释放栈内存,对象销毁

    四、奇葩的错误

    系统在什么情况下不会自动调用析构函数呢?显然,如果对象被建立在堆上,系统就不会自动调用。一个常见的例子是new…delete组合。但是好在调用delete的时候,析构函数还是被自动调用了。很罕见的例外在于使用布局new的时候,在delete设置的缓存之前,需要显式调用的析构函数,这实在是很少见的情况。

    我在栈上建树之后,显示调用析构函数,对象地址任然存在,甚至还可以往里面插入节点。。。

    其实析构之前最好先看看堆上的数据是不是已经被释放过了。

    #include <iostream>
    using namespace std;

    class A
    {

    private:
    int a;
    int* temp;
    bool heap_deleted;
    public:
    A(int _a);
    A(const A& _a);
    ~A();
    void change(int x);
    void show() const;
    };

    #endif

    ////////////a.cpp

    #include “a.hpp”
    A::A(int _a): heap_deleted(false)
    {
    temp = new int;
    *temp = _a;
    a = *temp;
    cout<< “A Constructor!” << endl;
    }

    A::A(const A& _a): heap_deleted(false)
    {
    temp = new int;
    *temp = _a.a;
    a = *temp;
    cout << “A Copy Constructor” << endl;
    }

    A::~A()
    {
    if ( heap_deleted == false){
    cout << "temp at: " << temp << endl;
    delete temp;
    heap_deleted = true;
    cout << “Heap Deleted!\n”;
    }
    else {
    cout << “Heap already Deleted!\n”;
    }

    void A::change(int x)
    {
    a = x;
    }

    void A::show() const
    {
    cout << "a = " << a << endl;
    }

    五、小结

    所以,一般不要自作聪明的去显示调用析构函数。

    展开全文
  • //开辟一个存放整数的存储空间,返回一个指向该存储空间的的地址 cout<<*p<<endl; delete p;//释放该空间 char *p_c; p_c=new char[10];//开辟一个存放字符数组(包括10个元素)的空间,返回首元素的...
  • 动态内存开辟new_delete new作用: 1.申请空间 2.调动构造函数初始化对象 delete作用: 1.调动析构函数析构对象 2.释放空间 通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型...

    动态内存开辟new_delete

    new作用:

    1.申请空间
    2.调动构造函数初始化对象
    delete作用:
    1.调动析构函数析构对象
    2.释放空间

    通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配

    有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。

    当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。
    当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。

    在C++中,申请和释放堆中分配的存贮空间,分别使用new和delete的两个运算符来完成,


    其使用的格式如下:

    类型名 指针变量名 = new 类型名(初始化式);
    delete 指针变量名;

    int *pi=new int(0);  //用初始化式来显式初始化:

    delete pi;     //当pi生命周期结束时,


    必须释放pi所指向的目标
    注意这时释放了pi所指的目标的内存空间,也就是撤销了该目标,称动态内存释放,但指针pi本身并没有撤销。

    对于数组进行动态分配的格式为:

    类型名 指针变量名=new 类型名[下标表达式];
    Delete [ ]指针变量名;

    int *pi = new int[10];  //创建一个int类型的数组
    delete []pi;             //删除数组

    两式中的方括号是非常重要的,两者必须配对使用。如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。
    delete [ ]的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。


    例子:

    <span style="font-size:18px;">class Test
    {
    public:
    	Test(int d = 0):data(d)
    	{}
    	~Test()
    	{}
    private:
    	int data;
    }
    
    int main()
    {	
    	Test *pt = new Test(100);   //创建一个对象,并初始化为100
    	delete pt;
    
    	Test *pa = new Test[100];    //创建100个对象,按默认值初始化
    	delete []pa;
    
    	return 0;
    }</span>

    强调:由堆区创建对象数组,只能调用缺省的构造函数,不能调用其他任何构造函数。
    如果没有缺省的构造函数,则不能创建对象数组。


    malloc和free与new和delete的区别:

    C语言中的malloc只负责申请空间,free只负责释放空间
    C++语言中的new不仅负责空间的申请,还负责为对象初始化,
    delete不仅负责空间的释放,之前还要析构对象

    指针使用的几个问题:


    1.动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。


    2.指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),
    释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针。

    3.内存泄漏(memory leak)和重复释放。new与  delete 是配对使用的, delete只能释放堆空间。
    如果new返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,
    因为该空间可能已另分配,所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。

    4.动态分配的变量或对象的生命期。无名对象的生命期并不依赖于建立它的作用域,
    比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因。
    但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错。

    展开全文
  • 1、new和delete基本用法 1)在C语言中是利用库函数malloc和free来分配和撤销内存空间的 C++编译器提供了较为方便并且功能强大... //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针) new int(1...

    1、new和delete基本用法

    1)在C语言中是利用库函数malloc和free来分配和撤销内存空间的
    C++编译器提供了较为方便并且功能强大的运算符new和delete来取代malloc和free函数
    2)虽然为了与C语言兼容,C++中仍保留了malloc和free函数,但不建议使用
    new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
    new int(100); //开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
    new char[10]; //开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
    new int[5][4]; //开辟一个存放二维整型数组(大小为5*4)的空间,返回首元素的地址
    float *p=new float (3.14159); //开辟一个存放单精度数的空间,并指定该实数的初值为3.14159,将返回的该空间的地址赋给指针变量p
    3)new和delete运算符使用的一般格式为:
    在这里插入图片描述类对象的动态建立和释放
    使用类名定义的对象都是静态的,在程序运行过程中,对象所占的空间是不能随时释放的。但有时人们希望在需要用到对象时才建立对象,在不需要用该对象时就撤销它,释放它所占的内存空间以供别的数据使用。这样可提高内存空间的利用率。
    C++中,可以用new运算符动态建立对象,用delete运算符撤销对象
    比如:
    Box *pt; //定义一个指向Box类对象的指针变量pt
    pt=new Box; //在pt中存放了新建对象的起始地址
    在程序中就可以通过pt访问这个新建的对象。如
    cout<height; //输出该对象的height成员
    cout<volume( ); //调用该对象的volume函数,计算并输出体积
    C++还允许在执行new时,对新建立的对象进行初始化。如
    Box *pt=new Box(12,15,18);
    这种写法是把上面两个语句(定义指针变量和用new建立新对象)合并为一个语句,并指定初值。这样更精炼。
    新对象中的height,width和length分别获得初值12,15,18。调用对象既可以通过对象名,也可以通过指针。
    在执行new运算时,如果内存量不足,无法开辟所需的内存空间,目前大多数C++编译系统都使new返回一个0指针值。只要检测返回值是否为0,就可判断分配内存是否成功。
    ANSI C++标准提出,在执行new出现故障时,就“抛出”一个“异常”,用户可根据异常进行有关处理。但C++标准仍然允许在出现new故障时返回0指针值。当前,不同的编译系统对new故障的处理方法是不同的。
    在不再需要使用由new建立的对象时,可以用delete运算符予以释放。如
    delete pt; //释放pt指向的内存空间
    这就撤销了pt指向的对象。此后程序不能再使用该对象。
    如果用一个指针变量pt先后指向不同的动态对象,应注意指针变量的当前指向,以免删错了对象。在执行delete运算符时,在释放内存空间之前,自动调用析构函数,完成有关善后清理工作。

    #define _CRT_SECURE_NO_WARNINGS
    #include <iostream>
    using namespace std;
    //1、
    //C语言   malloc free
    //C++	  new delete 操作符
    
    //2、 new可以在堆上分配 基础类型变量 数组变量 类变量
    
    //3、
    
    //基础类型
    void main81()
    {
    
    	int *p = (int *)malloc(sizeof(int ));
    	*p = 10;
    	free(p);
    
    	int *p2 = new int;	//分配基础类型
    	*p2 = 20;
    	delete p2;
    
    	int *p3 = new int(30);
    	printf("*p3 : %d\n", *p3);
    	delete p3;
    
    	system("pause");
    }
    
    //分配数组变量
    void main82()
    {
    	//C语言分配数组
    	int *p = (int *)malloc(sizeof(int) * 10);//int array[10];
    	p[0] = 1;	//赋值
    	free(p);
    
    	//C++分配
    	int *p2 = new int[10];
    	p[1] = 2;	//赋值
    	delete []p2;	//释放
    	
    	system("pause");
    }
    
    class Test {
    public:
    	Test(int _a)
    	{
    		a = _a;
    		cout << "构造函数执行" << endl;
    	}
    	~Test()
    	{
    		cout << "析构函数执行" << endl;
    	}
    private:
    	int a;
    };
    //分配对象
    //相同和不同 new能自动执行类的构造函数,delete操作符能执行类的析构函数
    void main()
    {
    	//C语言
    	Test *pT1 = (Test *)malloc(sizeof(Test));
    	free(pT1);
    
    	//C++
    	Test *pT2 = new Test(10);	//10是传参
    	delete pT2;
    
    	system("pause");
    }
    

    new和malloc 深入分析
    混用测试、异同比较
    结论: malloc不会调用类的构造函数
    Free不会调用类的析构函数

    展开全文
  • 在开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和...

    在开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数mallocfree来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符newdelete来取代mallocfree函数。

    在C++中因为newdelete是运算符,不是函数,因此执行效率高。

    虽然为了与C语言兼容,C++仍保留mallocfree函数,建议不用mallocfree函数,而用newdelete运算符。

    new int; // 开辟⼀个存放整数的存储空间,返回⼀个指向该存储空间的地址(即指针)	
    				
    new int(100); // 开辟⼀个存放整数的空间,并指定该整数的初值为100,返回⼀个指向该存储空间的地址		
    				
    new char[10]; // 开辟⼀个存放字符数组(包括10个元素)的空间,返回⾸元素的地址		
    				
    new int[5][4];	// 开辟⼀个存放⼆维整型数组(⼤⼩为5*4)的空间,返回⾸元素的地址		
    				
    float *p = new float(3.14159); // 开辟⼀个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p		
    
    #include <iostream>
    #include <cstdlib>
    
    using namespace std;
    
    class Test{
    	public:
    		Test(){
    			m_a = 0;
    			m_b = 0;
    			cout << "0,0 构造" << endl;
    		}
    		
    		Test(int a, int b){
    			m_a = a;
    			m_b = b;
    			cout << "a = " << m_a << ", b = " << m_b << "构造 " << endl;
    		}
    	
    		void setA(int a){
    			m_a = a;
    		}
    		
    		void setB(int b){
    			m_b = b;
    		}
    	
    		void printT(){
    			cout << "a = " << m_a << ", b = " << m_b << endl;
    		}
    	
    		~Test(){
    			cout << "a = " << m_a << ", b = " << m_b << "析构 " << endl;
    		}
    		
    	private:
    		int m_a;
    		int m_b;
    };
    
    
    //C语言中
    void test1(){
    	
    	int* p = (int*)malloc(sizeof(int));
    	*p = 10;
    	
    	cout << *p << endl;
    	
    	if (p != NULL) {
    		free(p);
    		//delete p; //delete 可以释放malloc的开辟的内存
    	}
    
    	int* array_p = (int*)malloc(sizeof(int) * 10);
    	for (int i = 0; i < 10; i++) {
    		array_p[i] = i + 10;
    	}
    
    	for (int i = 0; i < 10; i++) {
    		cout << array_p[i] << endl;
    	}
    
    	if (array_p != NULL) {
    		free(array_p);
    	}
    
    
    	cout << " --------  " << endl;
    
    	Test* tp = (Test*)malloc(sizeof(Test)); //不会调用对象的构造函数
    	//p(10, 20);
    	tp->setA(10);
    	tp->setB(20); //malloc出来的对象指针,只能够通过成员函数来进行初始化
    	tp->printT();
    
    	if (tp != NULL) {
    		free(tp); //不会调用对象的析构
    	}
    }
    
    //malloc 和free 在对于普通变量是可以混合使用的,但是malloc和free是函数,
    //new 和delete 是操作符。不是一个函数。
    
    //C++中的new delete
    void test2(){
    	//new 能够完成所有malloc的需求
    	int* p = new int; //在堆上动态开辟4个字节
    	*p = 10;
    	cout << *p << endl;
    
    	if (p != NULL) {
    		//delete p; //delete 一个变量
    		free(p); //用new开辟的内存, free也能够释放。
    	}
    
    	cout << "-----" << endl;
    
    	int* array_p = new int[10];
    	for (int i = 0; i < 10; i++) {
    		array_p[i] = i + 10;
    	}
    	for (int i = 0; i < 10; i++) {
    		cout << array_p[i] << endl;
    	}
    
    	if (array_p != NULL) {
    		delete[]   array_p; //delete 一个数组  // delete 数组的时候,虽然[]可以省略,程序运行的时候会自动处理和优化,但是为了方便代码的阅读,在delete数组的时候,需要在delete后面加上 []
    	}
    
    
    	cout << "-------" << endl;
    	//Test *tp = new Test(10, 20);//调用了有参数的构造函数 //new 在创建一个对象的时候,会调用对象的构造函数
    	Test* tp = new Test;//调用了无参构造函数
    	tp->printT();
    	if (tp != NULL) {
    		delete tp; //delete在释放一个对象指针的时候,会调用对象析构函数
    		tp = NULL;
    	}
    }
    
    int main(void){
    	//test1();
    	test2();
    
    	return 0;
    }
    
    • new 运算符动态分配堆内存
      使用形式:

      指针变量 = new 类型(常量);
      指针变量 = new 类型[表达式];

    作用:从堆分配一块“类型”大小的存储空间,返回首地址
    其中:“常量”是初始化值,可缺省创建数组对象时,不能为对象指定初始值

    • delete 运算符释放已分配的内存空间
      使用形式:

      delete 指针变量;
      delete[] 指针变量;

    其中:“指针变量”必须是一个 new 返回的指针


    注:

    用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。

    总结:

    • malloc不会调用类的构造函数,而new会调用类的构造函数
    • free不会调用类的析构函数,而delete会调用类的析构函数
    展开全文
  • 我在学习动态开辟和释放内存的时候,在我执行下面代码时,发现用delete释放 掉后,该指针仍然可以使用,说明delete释放掉的是存放对象空间,而原来的 指针仍然存在,可以继续使用。 class Point { public: Point...
  • 系统开辟了一段内存空间,存放一个Box类对象,同时调用该类的构造函数,完成对象初始化。用new运算符动态分配内存后,将返回一个指向新对象的指针的值,即所分配的内存空间的起始地址。需要定义一个指...
  • 如果形参为变量的引用名,实参为变量名,则在调用函数进行虚实结合时,并不是为形参另外开辟一个存储空间(常称为建立实参的一个拷贝), 而是把实参变量的地址传给形参(引用名),这样引用名也指向实参变量。...
  • 我现在有几个类,Layer,Feature,Layer类有addFeature函数,存到...我觉得应该是addFeature函数没有为子类开辟出存储空间,所以无法存放子类对象,请问如何解决,才能让addFeature函数根据类型来动态分配存储空间呢?
  • java对象数组[TOC]概念数组的定义类型 为对象类型使用动态初始化:1、声明并开辟空间2、赋值3、循环遍历打印静态初始化:1、声明并初始化2、循环遍历数组代码package demo1;import been.Animal;public class ...
  • 对象数组

    2014-06-10 19:25:36
    对象数组所谓的对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中读者一定要清楚一点:数组一定要先开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象都是null值,则在使用的时候数组中的...
  • c++动态内存管理

    2018-07-26 19:48:14
    c语言中使用malloc(进行动态开辟空间)、calloc(动态开辟空间,函数在返回前把内存初始化为0)、realloc(用于增容,用于修改一个原先已经分配的内存块大小)、free进行动态内存管理 c++通过new 和 delete动态...
  • 动态内存

    2018-05-14 23:47:12
    (3)当原空间后面没有足够的空间后,重新开辟空间,并将原空间释放,返回新空间的地址;2.C++动态内存管理:new /delete(1)new/delete的目的:为了维持C++的自定义类型的机制:保证创建对象时初始化(2...
  • 一、对象数组 ...1.声明并开辟空间 Person[] pers = new Person[长度];2.赋值 for(int i=0;i<pers.length;i++){  pers[i] = new Person(); }3.使用 for(int i=0;i<pers.length;i++){  pers[...
  • 在堆上创建对象需要用到动态开辟空间,需要使用new new一个新对象分为两步: 调用operator new()在堆上查找合适大小的空间分配给新对象; 调用构造函数构造对象,对新开辟空间进行初始化; 3.设计一个类只能在...
  • java对象数组

    2018-09-30 14:59:05
    这句话还有开辟数组空间的作用 还需要对数组中的每个元素进行单独的实例化 静态初始化: 类名 数组名 ={new 构造方法(),new 构造方法(),new 构造方法()} 动态初始化: 类名 对象数组名[] = new 类名(number) 再一一...
  • 创建对象的方式

    2020-01-27 17:22:38
    在堆储存区开辟了一块空间,其对象的引用存储在栈存储区上。 2.反射机制 java的反射机制指在运行状态中,对于任意一个类,我们可以获取这个类的属性和方法,对于任意一个对象,我们可以调用这个对象的方法和属性...
  •  因为每个对象都由相应的数据结构与方法相构成,一个程序可能有多个属于同一个类的对象,而每个对象的数据结构应该是不一的,但方法是相同的,若为每个对象开辟内存空间来存储方法,必然是对内存空间极大的浪费。...
  • 面向对象的思想

    2015-08-28 08:38:25
    堆:是由程序员自己开辟空间 栈:是由机器动态分配 外部函数不能直接访问对象的成员变量 调用成员方法通过对象的指针来调用对象的方法 先初始化父类,再初始化子类 带有参数的构造方法 初始化...
  • (Java)对象数组

    2020-01-01 22:21:02
    需要注意的是数组一定要先开辟空间,但是因为其是引用数据类型,所以数组中的每一个对象都是 null 值,则在使用时数组中的每一个对象必须分别进行实例化操作 类 对象数组名称[] = new 类[数组长度]; 文章目录一、...
  • 动态创建对象:程序在运行期间才为对象开辟空间 如果我们想要只能在堆上创建对象,可能我们会想到在类里把构造函数声明成为私有的,这样一来我们就不能在外面直接定义对象,以为系统无法调用构造函数了。 但此时...
  • python动态类型

    2019-10-01 15:09:25
    python是动态语言。不需要事先声明变量类型,同一变量可以被赋值为不同的对象类型。 变量、对象、引用 ...创建被赋值的对象,即在内存中开辟一块空间,用于保存对象的信息。本例来说是一个整数对象3...
  • C语言中动态内存管理

    2019-08-20 13:14:09
    // 在栈上开辟10个字节的连续空间 上述的开辟内存方式有两个特点: 1)空间开辟的大小是固定的 2)数组在声明的时候,必须指定数组的长度,它所需要的内存在 “编译” 时分配 3)静态内存分配都是在栈上开辟空间 ...
  • javascript的创建对象

    2020-07-09 10:30:04
    在计算机中,是开辟一个内存空间,存储一个被描述事物的数据。即对应着一个事物的数据模型。(虚拟现实) 对应的事件的功能,行为。在对象中用方法来表示。方法从根本上来说,就是一个函数。 创建对象的方式: 1,...
  •    所谓对象数组,就是指包含了一组相关的对象,但是在对象数组的使用中读者一定要清楚一点:数组一定要开辟空间,但是因为其是引用数据类型,所以数组里面的每一个对象都是 null 值,则在使用的时候数组中的每一...
  • 动态赋值变量

    2021-02-18 18:18:39
    开辟一块空间 2. 将值赋值到开辟空间 引用类型的话 就是new的过程 1. 创建一个空对象,将它的引用赋给 this,继承函数的原型。 2. 通过 this 将属性和方法添加至这个对象 3. 最后返回 this 指向的新对象...
  • iOS静态方法与动态方法

    千次阅读 2015-09-19 11:00:24
     因为每个对象都由相应的数据结构与方法相构成,一个程序可能有多个属于同一个类的对象,而每个对象的数据结构应该是不一的,但方法是相同的,若为每个对象开辟内存空间来存储方法,必然是对内存空间极大的浪费。...
  • java对象及其引用

    2020-06-01 16:27:11
    Java对象及其引用 先搞清楚什么是堆,什么是栈。 Java开辟了两类存储区域,对比...堆 由new等指令创建的对象和数组 可以动态地分配内存大小,生存期也不必事先告诉编译器 由于要在运行时动态分配内存,存取速度较慢 由

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 374
精华内容 149
关键字:

对象开辟动态空间