C++/C#中堆栈、对象内存模型、深浅拷贝、Array.Clone方法
转载自:http://blog.csdn.net/jarvischu/article/details/6425534
目录
1. C++/C#中对象内存模型..................................................................................................... 1
1.1. 栈内存与堆内存...................................................................................................... 1
1.1.1. 栈内存........................................................................................................... 1
1.1.2. 堆内存........................................................................................................... 1
1.1.3. 栈内存与堆内存比较................................................................................... 1
1.2. 值类型与引用类型...................................................................................................2
1.3. 内存模型.................................................................................................................. 3
2. 深拷贝和浅拷贝..................................................................................................................4
2.1. 案例1.........................................................................................................................4
2.2. 理解.......................................................................................................................... 5
2.3. 案例2........................................................................................................................ 6
3. System.Array的Clone() ........................................................................................................8
1. C++/C#中对象内存模型
1.1. 栈内存与堆内存栈内存与堆内存
1.1.1. 栈内存
l 由编译器自动分配和释放
l 用于保存一些局部变量、函数的参数等
理解:
l int a;
那么编译器会自动在栈中给变量a分配一个sizeof(int)大小的内存
1.1.2. 堆内存
l 由程序员手动申请和[释放]
在C++中,通过new申请,编译器不会释放,必须通过delete释放。
在C#中,通过new申请,因编译器的GC(垃圾回收机制),程序员省去了delete操作
l char* p = new char[10];//C++
char[] p = new char[10];//C#
首先,编译器分配一个栈内存保存变量p
之后,编译器分配一个堆内存,大小为sizeof(char)*10
最后,将堆内存的首地址存放在p中。
1.1.3. 栈内存与堆内存比较
u 内存分配
栈:后进先出;由编译器分配相应类型大小;分配的大小受限于栈区大小
堆:随意分配;由程序员手动申请指定大小;分配的大小受限于计算机的虚拟内存
u 效率
栈:高
堆:相对栈低
1.2. 值类型与引用类型
u 简单理解
值类型变量保存的是实际数据,引用类型变量保存的实际数据所在的内存地址。
u 存储区别
值类型数据存储在栈内存中,引用类型变量对应的实际数据存储在堆内存(变量本身存储在栈内存中,通常是四个字节,保存着一个地址数值)
u C++类型
值类型:int,float,double,char,enum
引用类型:array,structure,class
u C#类型
值类型:struct,enum
引用类型:class,delegate,array,interface
为什么这里没有int,float等类型了?(写漏了?)
回答这个问题,请看MSDN中的一句话:
Types that you define by using the struct keyword are value types; all the built-in numeric types are structs. (C#)
这里有三点强调一下:
ü struct(结构体)类型是值类型
ü built-in numberic types(内建数值类型,即int,float等)都是结构体,如int对应了System.Int32结构体
ü 具MSDN记载,System.Int32就是int的别名
图 1 C#中类型概览
1.3. 内存模型
图 2 值类型内存模型
图 3 引用类型内存模型(C#为例,C++类似)
2. 深拷贝和浅拷贝
2.1. 案例1
以图3中的Person类为例。(Name 和 Age是Person类的public 属性)
上面的语句执行结果是什么?
这里涉及到深拷贝和浅拷贝,理解了这两个概念后,问题的答案也就出来了。
2.2. 理解
当将对象a赋值给另一个对象b时,就会执行拷贝函数。
深拷贝:将a 的完完全全复制一份,然后赋值给b(Copy Value)(可以理解成副本)
浅拷贝:将a 的引用复制一份,然后赋值给b(Copy Reference)(可以理解成别名)
图4中:
Person b = al;
浅拷贝,它只是将对象a的引用(就是变量a,更确切的说是a中保存的内存地址)赋值给了变量b。这样,a和b就指向了同一块内存。
Person c = new Person(a.Name,a.Age);
深拷贝,它将对象a的引用以及它所指向的内存区的数据都复制了一份,然后赋值给了b。这样,a和b都指向了各自地址不同,但数据相同的内存区。
这样,上面问题的答案也出来了,输出:
//2013-10-23修正
Chu
Jarvis
图 4 深浅拷贝
2.3. 案例2
好了,我们趁热打铁,再看另一种情况。
Country类和Person类的定义如下:
则下面的代码输出结果是什么?
- Country china = new Country(“中国”,960);
- Person a = new Person(“Jarvis”,22,china);
- Person b = a;
- Console.WriteLine(a.MotherLand.CountryName);
- Console.WriteLine(b.MotherLand.CountryName);
- china.CountryName = “共和国”;
- Console.WriteLine(a.MotherLand.CountryName);
- Console.WriteLine(b.MotherLand.CountryName);
这个案例中涉及了两次浅拷贝,
一次是MotherLand = land; ,
一次是Person b = a;。
它体现的内容是:
将一个含有对象类型属性(MotherLand)的对象(a),直接赋值给另一个对象(b)。
那么这个拷贝(很明显是浅拷贝)的过程究竟是怎么样的?内存中数据的状态又是如何的?
答案是:
共和国
共和国
(你答对了么?)
看一下我的图解。
图 5 含对象属性的拷贝
如果将2处的“中国”变成了“共和国”,当然输出结果是两行“共和国”咯
3. System.Array的Clone()方法
为什么要特意讲这个Clone()方法呢?它有什么特别么?
说特别,可能有点特别,但是讲它的主要原因不在于此,而是因为这个方法让我纠结了很久,因为MSDN中,说它是浅拷贝。可是下面的代码输出的结果却与我想的不一样:
- int[] arrOriginal = { 1, 2, 3, 4 };
- int[] arrCopyDirect = arrOriginal; //直接浅拷贝
- int[] arrCopyClone = (int[])arrOriginal.Clone(); //Clone方法
- ShowArray(arrOriginal); //ShowArray方法就是简单的把数组的每个元素都显示出来ShowArray(arrCopyDirect);
- ShowArray(arrCopyClone);
- arrOriginal[0] = 0;
- Console.WriteLine();
- ShowArray(arrOriginal);
- ShowArray(arrCopyDirect);
- ShowArray(arrCopyClone);
输出的结果是:
说明Clone方法是把arrOriginal数组中的元素都另外拷贝了一份赋值给了arrCopyClone数组,所以赋值结束后,改变arrOriginal数组的元素的值(arrOriginal[0] = 0),arrCopyClone就不受影响了(arrCopyClone[0] = 1),这是浅拷贝么?
有点让人疑惑。
但是如果用一个Person类类型的数组而不是int类型的数组去测试时,可以发现的确源数组A赋值给新数组B 后,A中元素如果改变,B也相应的变化了。
这个让我在费了很长时间才理解,这个过程中,我就对上面提到的几个知识点做了进一步理解。
最终我找到了答案,MSDN上的解释是:
A shallow copy of an Array copies only the elements of the Array, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new Array point to the same objects that the references in the original Array point to.
意思就是说:
不管数组中的元素是值类型(Value Types,如int)还是引用类型(Reference Types,如Person),该方法都是将数组的所有元素都拷贝到另一个数组中。
这样的结果就是:如果原数组中的元素都是值类型,这个就相当于深拷贝,如果原数组中的元素是引用类型,那么就相当于浅拷贝。
所以我认为,MSDN上直接把它说成是Shallow Copy还是有待商榷的。
C++/C#中堆栈、对象内存模型、深浅拷贝、Array.Clone方法的更多相关文章
- C++对象内存模型1(堆栈模型)
对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立 ...
- C++对象内存模型1(堆栈模型)(转)
对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立 ...
- 理论与实践中的 C# 内存模型
转载自:https://msdn.microsoft.com/magazine/jj863136 这是该系列(包含两部分内容)的第一部分,这部分将以较长的篇幅介绍 C# 内存模型. 第一部分说明 C# ...
- C#的对象内存模型
转载自:http://www.cnblogs.com/alana/archive/2012/07/05/2577893.html C#的对象内存模型: 一.栈内存和堆内存1.栈内存 由编译器自动分配和 ...
- C++对象内存模型2 (虚函数,虚指针,虚函数表)
从例子入手,考察如下带有虚函数的类的对象内存模型: class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1 ...
- (转)c#对象内存模型
对象内存模型 C#的对象内存模型写这篇博客的主要目的是为了加深自己的理解,如有不对的地方,请各位见谅. C#的对象内存模型: 一.栈内存和堆内存1.栈内存 由编译器自动分配和释放,主要用来保存一些局部 ...
- 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响
首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...
- Swift 对象内存模型探究(一)
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/zIkB9KnAt1YPWGOOwyqY3Q 作者:王 ...
- 对C++对象内存模型造成的影响(类/对象的大小)
首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...
随机推荐
- django下的ckeditor 5.0 文本编辑器上传功能。
完整的后台界面怎么可以没有文本编辑器,但是django的admin界面很疑惑,没有自带文本编辑器,好在网上有不少成型的库可以用 我用的是ckeditor编辑器,安装和配置我引用别人的博客 这篇博客配置 ...
- C语言中的const
今天探讨const,首先来说是将变量常量化.为什么要将变量常量化,原因有诸多好处有诸多.比如可以使数据更加安全不会被修改! 但是这个词有几个点要注意,那就是他究竟修饰了谁? 1.const int a ...
- MySQL复制表结构表数据
MySQL复制表结构 表数据 1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete ...
- Oracle -----视图
视图简介: 视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改.视图基于的表称为基表.视图是存储在数据字典里的一条select语句. 通过创建视图可以提取数 ...
- 3.25考试(hnoi难度)----神奇的一日游
T1怕老婆 有一天hzy9819,来到了一座大城市拥有了属于他自己的一双滑板鞋.但是他还是不满足想要拥有属于自己的一栋楼,他来到了一条宽敞的大道上,一个一个记录着这些楼的层数以方便自己选择. hzy9 ...
- hdu 3054 Fibonacci 找循环节的公式题
Fibonacci Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Proble ...
- HDU-4507 吉哥系列故事——恨7不成妻 数位DP
题意:给定区间[L, R]求区间内与7无关数的平方和.一个数当满足三个规则之一则认为与7有关:1.整数中某一位是7:2.整数的每一位加起来的和是7的整数倍:3.这个整数是7的整数倍: 分析:初看起来确 ...
- [转载] 一致性问题和Raft一致性算法
原文: http://daizuozhuo.github.io/consensus-algorithm/ raft 协议确实比 paxos 协议好懂太多了. 一致性问题 一致性算法是用来解决一致性问题 ...
- openerp安装记录及postgresql数据库问题解决
ubuntu-14.04下openerp安装记录1.安装PostgreSQL 数据库 a.安装 sudo apt-get install postgresql 安装后ubu ...
- thinkphp自动验证方法的使用
建一个表单: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...