C++ : 从栈和堆来理解C#中的值类型和引用类型
C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的。但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆。
栈(stack)是类似于一个先进后出的抽屉。它的体积是有限的,一般为2M左右。
而堆(heap)则相对来说体积可以很大,这一般跟计算机的虚拟内存设置有关系。
栈中存取对象的内存是自动回收的,用完即销毁了,一般方法内部的变量和参数都是通过栈来存取的(但也正因为如此,它们的生命周期很短)。但它的问题是,体积有限。
一些大的对象,我们可能要通过堆来创建它。程序员可以控制这些对象什么时候创建,什么时候销毁。这无疑带来了灵活性,也同时带来了一些风险,事实上,相当一部分的程序的崩溃都是因为不恰当地使用了堆,以及没有及时清理在堆上申请的内存。或者反过来说,可能会清理多次(这也会导致崩溃)。
通常来说,如果希望某个对象或者变量的生命更长一些,也可以将其作为全局变量或者静态变量。但那样又导致了它们必须等到程序结束才会释放。
下面我用一个例子来演示一下这个问题
#include <iostream>
using namespace std;
class human{
public:
void Talk();
~human(){cout<<"析构函数在工作..."<<endl;}
private:
int age;
};
void human::Talk(){
cout<<"Hello"<<endl;
}
int main()
{
human h;//创建一个human对象,这个对象就生存在栈上,它所需的大小是根据其成员决定的
cout<<"h的大小为:"<<sizeof(h)<<endl;
cout<<"h的地址是:"<<&h<<endl;
h.Talk();
human *p=new human();//通过new关键字,是在堆上面创建一个对象,它所申请的空间也是内部成员决定的.这里也是4
cout<<"p的大小为:"<<sizeof(p)<<endl;
cout<<"p的地址为:"<<p<<endl;
p->Talk();
delete p;
//删除p这个指针指向的堆上面的内存.如果用完该对象,我们不删除,那么该内存就一直存在,并不会自动删除.这就称为内存泄漏.
//如果类型定义了析构函数,此时将调用它(反之,如果一个对象是在堆上创建的,那么除非调用delete语句,否则析构函数不会运行
cout<<"p的地址为:"<<p<<endl;//我们只是删除了该块内存上面的数据,地址还是存在的
//建议在删除p之后,将其置为0
//p=0;
//delete p;//但如果再次删除,又会发生崩溃,因为该内存已经没有了.
return 0;
}
有两句“析构函数在工作”,第一句是p这个指针所指向的堆上面那个对象的析构,而最后那句在是h这个在栈上的对象的析构。
有兴趣的朋友,可以将delete语句注释掉,则只会看到一个析构过程。
我们可以做得更加复杂一些来看
#include <iostream>
using namespace std;
class human{
public:
void Talk();
~human(){cout<<"析构函数在工作..."<<endl;}
private:
int age;
};
void human::Talk(){
cout<<"Hello"<<endl;
}
int main()
{
human h;//创建一个human对象,这个对象就生存在栈上,它所需的大小是根据其成员决定的
cout<<"h的大小为:"<<sizeof(h)<<endl;
cout<<"h的地址是:"<<&h<<endl;
h.Talk();
human *p=new human();//通过new关键字,是在堆上面创建一个对象,它所申请的空间也是内部成员决定的.这里也是4
cout<<"p的大小为:"<<sizeof(p)<<endl;
cout<<"p的地址为:"<<p<<endl;
p->Talk();
human *p2=p;//创建另外一个指针,让他也保存一样的地址。
cout<<"p2的大小为:"<<sizeof(p2)<<endl;
cout<<"p2的地址为:"<<p2<<endl;
p2->Talk();
delete p;
//删除p这个指针指向的堆上面的内存.如果用完该对象,我们不删除,那么该内存就一直存在,并不会自动删除.这就称为内存泄漏.
//如果类型定义了析构函数,此时将调用它(反之,如果一个对象是在堆上创建的,那么除非调用delete语句,否则析构函数不会运行
cout<<"p的地址为:"<<p<<endl;//我们只是删除了该块内存上面的数据,地址还是存在的
//建议在删除p之后,将其置为0
//p=0;
//delete p;//但如果再次删除,又会发生崩溃,因为该内存已经没有了.
//delete p2;//不光是p不能在删除,所以相同的指针都不能再删除了,否则就崩溃了
return 0;
}
知道了上述原理之后,我们就不难理解C#中的值类型和引用类型了。
- 值类型是指基础数据类型(除了string),结构体,枚举
- 引用类型是指类,接口,委托(其实类似指针),string,object
值类型是生存在栈上,好处是效率高,不需要额外的回收。但它的空间是有限的,所有一般只适合基础类型(char,byte,int,short,long,bool,double,float等)。
引用类型则生存在堆上,但在栈上有一个指针(因为在堆上的对象都是匿名的,指针此时起到了一个别名的作用,其实就是等同于引用的概念,固有引用之说)
引用类型既然生存在堆上,那么按照C++的情况就必须我们自己去销毁它。但从上面的演示就不难看出,何时销毁它,以及会不会忘记销毁它,或者重复销毁它,都是一个很大的难题。所以在.NET Framework中,通过CLR中垃圾回收器(GC)来负责回收。一般的程序员不需要特别在意这个过程。
最后有意思的是,C#中的INT,其实并不等同于C++中的INT,大家如果有兴趣的话,可以看一下,它其实是一个结构体。
C++ : 从栈和堆来理解C#中的值类型和引用类型的更多相关文章
- 【译】.NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)
作者: Edison Chou 来源: 博客园 发布时间: 2014-09-03 15:59 阅读: 318 次 推荐: 2 原文链接 [收藏] 原文作者:Shivprasad k ...
- .NET中的六个重要概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要翻译 一来是为了感受国外优秀技术社区知名博主的高质量文章,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果,最后也是为了锻炼一下自己的英文读写能力.因为是首次翻译英文文章(哎,原谅我这个 ...
- [转] .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱
为何要转载 一来是最近面试了几家公司,发现问的还都是这些的基础知识,二来是为了复习对.NET技术的基础拾遗达到温故知新的效果. 为什么有人说,不动笔不读书.我现在也是深有体会了,看过的东西不一定会记得 ...
- C#栈、堆的理解(2)
接上一遍博文有关值类型和引用类型的相关概念. 所有值类型数据存放:栈(内存) 引用类型的数据存放:堆(内存) 栈:可以认为是一本书的目录部分称其为栈.栈可快速检索,运行速度比堆大,而且栈的空间小得多. ...
- 图解C#的值类型,引用类型,栈,堆,ref,out
C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C#程序员都会接触到的概念,也是C#程序员面试经常考到的知识,随便搜搜 ...
- C#基础知识系列二(值类型和引用类型、可空类型、堆和栈、装箱和拆箱)
前言 之前对几个没什么理解,只是简单的用过可空类型,也是知道怎么用,至于为什么,还真不太清楚,通过整理本文章学到了很多知识,也许对于以后的各种代码优化都有好处. 本文的重点就是:值类型直接存储其值,引 ...
- 值类型,引用类型,栈,堆,ref,out
在网上收集... C#的值类型,引用类型,栈,堆,ref,out C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C# ...
- .NET六大剑客:栈、堆、值类型、引用类型、装箱和拆箱
.NET六大剑客:栈.堆.值类型.引用类型.装箱和拆箱 一.“堆”,“栈”专区 这两个字我相信大家太熟悉了,甚至于米饭是什么?不知道...“堆”,“栈”是什么?哦,这个知道... 之前我也写过一篇堆栈 ...
随机推荐
- Windows 多用户远程访问 Ubuntu 14.04桌面
使用X2Go实现多用户远程访问 Ubuntu 14.04桌面:VNC也可以,但是每次连接VNC就回新创建一个Seession,想要在下次远程登录的时候返回上次活动,需要记住开启的线程,这种繁琐的操作不 ...
- 常用网页标签重置CSS
做前端开发时常需要将网页中所有标签的格式清空,从而使各个浏览器标签样式一样.以下是网络上常见的CSS代码 /* =s Reset (by YUI 3) */ html{color:#000;} bod ...
- jquery+ajax 实现text框模糊搜索并可利用listbox实时显示模糊搜索列表结果
功能描述: text框中输入,text框下面的listbox中实时显示依据输入的内容进行模糊搜索的结果 js代码 $j(function() { $j("input[id='txtCos'] ...
- As input tri-stated
前些日子正好看到了riple兄的<一波三折--危险的"未分配"引脚>一文,颇受启发.正好最近也遇上了类似的问题,也可谓一波三折,还好最后摆平了,要不煮熟的鸭子可就要飞了 ...
- iOS 8 AutoLayout与Size Class自悟(转载)
iOS 8 AutoLayout与Size Class自悟 Size classiOS 8 AutoLayout 前言 iOS8 和iPhone6发布已经过去蛮久了,广大的果粉终于迎来了大屏iPhon ...
- hive-1.2.1安装步骤
一.Hive安装和配置 1.先决条件 已经安装好hadoop-2.4.1,hbase-1.0.0. 2.下载Hive安装包 当前Hive可到apache官网下载,选择的是hive-1.2.1.运行: ...
- C#隐藏(new)方法和重写(override)方法
在基类调用的时候 隐藏方法还是调用基类的方法 而重写方法调用的就是子类的中的方法 同时,当子类中的方法与父类或者所实现的接口中的扩展方法冲突时,那么此时相当于一个隐藏方法 基类调用或者接口调用的时候使 ...
- sql语句的学习(1)
一.创建表 CREATE TABLE `student` ( `id` ) NOT NULL AUTO_INCREMENT, `name` ) DEFAULT NULL COMMENT '姓名', ` ...
- MySQL的保留字查询
ADD ALL ALTER ANALYZE AND AS ASC AUTO_INCREMENT BDB BEFORE BERKELEYDB BETWEEN BIGINT BINARY BLOB BOT ...
- 数据库 Mysql内容补充一
mysql时间函数 --获取当前日期 select current_date(); --获取当前时间 select current_time(); --获取当前的日期和时间 select now(); ...