C++中栈和堆上建立对象的区别
在C++中类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* p=new A(),A*p=(A*)malloc();静态建立一个类对象,是由编译器为对象在栈空间中分配内存,通过直接移动栈顶指针挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。动态建立类对象,是使用new运算符将对象建立在堆空间中,在栈中只保留了指向该对象的指针。栈是由编译器自动分配释放 ,存放函数的参数值,局部变量的值,对象的引用地址等。其操作方式类似于数据结构中的栈,通常都是被调用时处于存储空间中,调用完毕立即释放。堆中通常保存程序运行时动态创建的对象,C++堆中存放的对象需要由程序员分配释放,它存在程序运行的整个生命期,直到程序结束由OS释放。而在java中通常类的对象都分配在堆中,对象的回收由虚拟机的GC垃圾回收机制决定。
1.下面的程序来看看静态建立和动态建立对象的区别
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 class student 5 { 6 public: 7 string name; 8 int age; 9 void sayhello(); 10 }; 11 void student::sayhello() 12 { 13 cout<<"my name is: "+this->name+" I am: "<<this->age; 14 cout<<"\n"; 15 } 16 student setname(string name) 17 { 18 student stu; 19 stu.age=12; 20 stu.name=name; 21 return stu; 22 } 23 int main() 24 { 25 student stu=setname("jim"); 26 stu.sayhello(); 27 return 0; 28 }
程序运行结果:my name is: jim I am: 12;
程序定义了一个student类,在setname函数中定义一个局部对象作为返回值。程序第18行静态构建了一个student对象stu,它在栈上分配空间,在函数调用结束后就销毁了,函数返回的类对应在内存中的值应该不存在啊?其实原来C++在用类作为函数的返回值时调用了类的拷贝构造函数,而且该拷贝构造函数是在堆上分配存储空间,后面再讨论这个问题。
在setname函数内的stu在函数调用结束后就销毁了,可以添加一个析构函数来证明:
在student类中加入析构函数:
student::~student() {cout<<this->name<<":gameover"<<endl; }
程序运行结果:
在sayhello()前,输出jim:gameover,即为setname()里的stu对象执行了析构函数。
如将setname函数改为:
student* setname(string name) {student stu;stu.age=12;stu.name=name;return &stu; }
main函数的调用改为:
int main() {student* p=setname("tom");p->sayhello();return 0; }
显然这里会出现问题,对象指针返回的是栈上的对象,在函数调用结束后已经销毁了,对象指针即为野指针,故程序在编译时会提示:warning C4172: returning address of local variable or temporary。解决这个问题我们自然想到把该对象构建在堆上即可。修改setname函数为下:
student* setname(string name){ student* stu= new student(); stu->age=12; stu->name=name; return stu;}
main函数的调用不变;程序正常运行输出:
上面输出结果并没有调用析构函数,在setname调用后,在main函数结束后也没有调用。在对上的对象需要程序员自己delete释放,将main改为如下:
int main() {student* p=setname("tom");p->sayhello();delete p;return 0; }
即加入delete p;运行结果:
C中用malloc函数来动态申请空间,该内存分配在堆上。这里可以验证,加入#include <malloc.h>,将setname函数改为如下:
1 student* setname(string name) 2 { 3 student* stu=(student*)malloc(sizeof(student)); 4 stu->age=12; 5 stu->name=name; 6 return stu; 7 }
为在student中加入构造函数:
student::student() {cout<<"constructor"<<endl; }
上面的程序执行到第5行会出错,原因是没有调用构造函数,stu->name根本就没有被初始化(string的构造函数没有被调用),所以不能赋值 。具体的解释是: 因为malloc只是分配堆内存(不会调用构造函数)它并不知道内存里要存的是什么。为此用new即可,将第3行代码改为:student* stu=new student;程序运行结果为下:
即程序调用了构造函数。若非要用malloc来申请内存可以将setname函数改为如下:
1 student* setname(string name) 2 { 3 student* stu=(student*)malloc(sizeof(student)); 4 new(stu) student; 5 stu->age=12; 6 stu->name=name; 7 return stu; 8 }
即加入了第4行程序正常运行,调用了构造函数。第4行大概可以理解为new了一个student对象,赋值转换为student的指针stu。
既然这样可以把第3行直接改为:student* stu;即
1 student* setname(string name) 2 { 3 //student*stu= new student; 4 student* stu; 5 new(stu) student; 6 stu->age=12; 7 stu->name=name; 8 return stu; 9 }
让说第4,5行的效果应该和第3行相同,编译程序提示:warning C4700: local variable 'stu' used without having been initialized,即stu没有初始化。 new(stu) student;和stu= new student;并不等价。第5行并不是初始化,这里可以看做第5行这种写法(之前还真没见过)是C++为兼容malloc内存申请的用法,一般情况下推荐肯定是用new关键字。
到此其实这里要说明的主题已经基本说明了,关于malloc的用法当申请的类的成员变量只包含基本的数据类型(数值型int,double等)(string等引用类除外)时是不会出错的。下面的列子可以证明;
1 #include<iostream> 2 #include<string> 3 #include <malloc.h> 4 using namespace std; 5 class course 6 { 7 public: 8 int id; 9 float score; 10 void printscore() 11 { 12 cout<<"id:"<<this->id; 13 cout<<" score:"<<this->score<<endl; 14 } 15 }; 16 17 course* setscore(int id,float score) 18 { 19 course* co= (course*)malloc(sizeof(course)); 20 co->id=id; 21 co->score=score; 22 return co; 23 } 24 int main() 25 { 26 course* cou=setscore(999,188.9); 27 cou->printscore(); 28 return 0; 29 }
程序运行结果如下:
程序第19行这样的用法没有问题,而之前的string类却有问题。这样看来,自定义类型作为类的成员时也应该会有问题,来看下面的代码:
1 #include<iostream> 2 #include<string> 3 #include <malloc.h> 4 using namespace std; 5 class course; 6 class student 7 { 8 public: 9 string name; 10 int age; 11 course cou; 12 void sayhello(); 13 ~student(); 14 student(); 15 }; 16 student::student() 17 { 18 cout<<"constructor"<<endl; 19 } 20 student::~student() 21 { 22 cout<<this->name<<":gameover"<<endl; 23 } 24 void student::sayhello() 25 { 26 cout<<"my name is: "+this->name+" I am: "<<this->age; 27 cout<<"\n"; 28 } 29 class course 30 { 31 public: 32 int id; 33 float score; 34 void printscore() 35 { 36 cout<<"id:"<<this->id; 37 cout<<" score:"<<this->score<<endl; 38 } 39 }; 40 course* setscore(int id,float score) 41 { 42 course* co= (course*)malloc(sizeof(course)); 43 co->id=id; 44 co->score=score; 45 return co; 46 } 47 student* setname_score(string name ,course* cou) 48 { 49 student* stu= (student*)malloc(sizeof(student)); 50 stu->age=12; 51 new(stu)student; 52 stu->cou.id=cou->id; 53 stu->cou.score=cou->score; 54 stu->name= name; 55 return stu; 56 } 57 int main() 58 { 59 course* cou=setscore(999,188.9); 60 student* stu=setname_score("jimm",cou); 61 stu->cou.printscore(); 62 stu->sayhello(); 63 return 0; 64 }
这段代码中把course类对象作为student的类成员。程序编译出错: error C2079: 'cou' uses undefined class 'course'。把course类的定义放在前面则没有错即:
1 #include<iostream> 2 #include<string> 3 #include <malloc.h> 4 using namespace std; 5 class course 6 { 7 public: 8 int id; 9 float score; 10 void printscore() 11 { 12 cout<<"id:"<<this->id; 13 cout<<" score:"<<this->score<<endl; 14 } 15 }; 16 class student 17 { 18 public: 19 string name; 20 int age; 21 course cou; 22 void sayhello(); 23 ~student(); 24 student(); 25 }; 26 student::student() 27 { 28 cout<<"constructor"<<endl; 29 } 30 student::~student() 31 { 32 cout<<this->name<<":gameover"<<endl; 33 } 34 void student::sayhello() 35 { 36 cout<<"my name is: "+this->name+" I am: "<<this->age; 37 cout<<"\n"; 38 } 39 course* setscore(int id,float score) 40 { 41 course* co= (course*)malloc(sizeof(course)); 42 co->id=id; 43 co->score=score; 44 return co; 45 } 46 student* setname_score(string name ,course* cou) 47 { 48 student* stu= (student*)malloc(sizeof(student)); 49 stu->age=12; 50 new(stu)student; 51 stu->cou.id=cou->id; 52 stu->cou.score=cou->score; 53 stu->name= name; 54 return stu; 55 } 56 int main() 57 { 58 course* cou=setscore(999,188.9); 59 student* stu=setname_score("jimm",cou); 60 stu->cou.printscore(); 61 stu->sayhello(); 62 return 0; 63 }
View Code
运行结果为:
上面程序setname_score函数中若不用new(stu)student;这种写法,则会出现未初始化的错误。这里完全可以将类的成员改为指针的形式,在初始化时用new在堆上分配存储。改写的代码如下:
1 #include<iostream> 2 #include<string> 3 #include <malloc.h> 4 using namespace std; 5 class course; 6 class student 7 { 8 public: 9 string* name; 10 int age; 11 course* cou; 12 void sayhello(); 13 ~student(); 14 student(); 15 }; 16 student::student() 17 { 18 cout<<"constructor"<<endl; 19 } 20 student::~student() 21 { 22 cout<<this->name<<":gameover"<<endl; 23 } 24 void student::sayhello() 25 { 26 cout<<"my name is: "+*(this->name)+" I am: "<<this->age; 27 cout<<"\n"; 28 } 29 class course 30 { 31 public: 32 int id; 33 float score; 34 void printscore() 35 { 36 cout<<"id:"<<this->id; 37 cout<<" score:"<<this->score<<endl; 38 } 39 }; 40 course* setscore(int id,float score) 41 { 42 course* co= (course*)malloc(sizeof(course)); 43 co->id=id; 44 co->score=score; 45 return co; 46 } 47 student* setname_score(string name ,course* cou) 48 { 49 student* stu= (student*)malloc(sizeof(student));//student*stu=new student;也一样,只是一个调用构造函数,一个不调用 50 stu->age=12; 51 stu->cou=new course();//这里用new建立对象 52 stu->cou->id=cou->id; 53 stu->cou->score=cou->score; 54 stu->name=new string(name);//new 55 return stu; 56 } 57 int main() 58 { 59 course* cou=setscore(999,188.9); 60 student* stu=setname_score("jimm",cou); 61 stu->cou->printscore(); 62 stu->sayhello(); 63 return 0; 64 65 }
View Code
上面程序运行结果为:
综上所述,C++中对象的建立可以在堆和栈上。分别为动态建立和动态建立的方式,构建堆上的对象时一般使用new关键字,而对象的指针在栈上。使用new在堆上构建的对象需要主动的delete销毁。C++对象可以在堆或栈中,函数的传参可以是对象(对象的拷贝),或是对象的指针。而在java中对象一般分配在堆上,对象的传值只有值类型,即对象的引用(地址),这样看来C++要灵活的多。关于c++数组的内存分配还有这里提到的拷贝构造函数,下次再讨论啊。上面的程序在VC++6.0编写通过。
转载于:https://www.cnblogs.com/xiaoxiaoqiang001/p/5557704.html
C++中栈和堆上建立对象的区别相关推荐
- C++ 栈和堆上建立对象的区别
在C++中类的对象建立分为两种,一种是静态建立,如A a:另一种是动态建立,如A* p=new A(),Ap=(A)malloc():静态建立一个类对象,是由编译器为对象在栈空间中分配内存,通过直接移 ...
- .NET中栈和堆的比较【转自:c#开发园地】
本文转自:C#开发园地 原文翻译的地址: http://www.cnblogs.com/c2303191/articles/1065675.html 压栈(入栈)=执行方法中的指令 .NET中栈和堆的 ...
- 【c++】【转】如何只在heap上创建对象,如何只在stack上建立对象?
http://www.cnblogs.com/chio/archive/2007/10/23/934335.html http://blog.csdn.net/szchtx/article/detai ...
- linux java 栈_关于Java中栈与堆的思考
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度比堆要快,仅次于直接位于C ...
- .NET中栈和堆的比较 #1
原文出处:http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.a ...
- .NET中栈和堆的比较(二)
尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(Garbage Collection),但是我们还是应该了解它们,以优化我们的应用程序.同时,还需要具备一些基础的内存管理工作机 ...
- .NET中栈和堆的比较1
原文出处: http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory. ...
- .net/c#中栈和堆的区别及代码在栈和堆中的执行流程详解之一(转)
http://www.codingthink.com/c/20121223/201212231458171.html 原文出处: http://www.c-sharpcorner.com/Upload ...
- java 栈 堆 区别_java中栈与堆的区别
1. 栈(stack)与堆(heap)都是Java用来在Ram(random access memory随机存取器)中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. ...
最新文章
- linux error log 换行,日志提示
- GlusterFS 安装与配置
- pytorch 测试 darknet
- Strong Consistency, 强一致性技术概述
- android项目引用java项目图解和注意事项
- LinkdedList
- [iOS]应用内支付(内购)的个人开发过程及坑!
- ImageView倒影效果
- python configparser模块来 读取 、 创建 和 修改 配置文件
- gravity和layout_gravity
- linux输入字符串到文件,[Linux文件]将用户输入的字符串写入文件实例
- GPRS,GSM,WAP三者有什么区别(ZT)
- 通过mysqladmin监控MySQL数据的服务器状态
- ios模拟器装ipa包_给iOS 模拟器“安装”app文件
- 简单的转盘抽奖html,一个很简单的H5的转盘抽奖的(主要用的是css3的属性)
- 1620:质因数分解
- 佳能相机G7 Mark Ⅱ (测光与对焦)
- ceph rbd扩容
- 伯俊软件获得阿里云原生核心授牌伙伴认证,共建新生态
- ps技巧:自动选择工具的使用