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) ...
随机推荐
- Linux 性能监测:Network
网络的监测是所有 Linux 子系统里面最复杂的,有太多的因素在里面,比如:延迟.阻塞.冲突.丢包等,更糟的是与 Linux 主机相连的路由器.交换机.无线信号都会影响到整体网络并且很难判断是因为 L ...
- 一SERVLET (1)
转载自http://www.cnblogs.com/xdp-gacl/p/3760336.html 一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公 ...
- 【leetcode❤python】409. Longest Palindrome
#-*- coding: UTF-8 -*- from collections import Counterclass Solution(object): def longestPalindro ...
- BZOJ 2756 奇怪的游戏(最大流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2756 题意:在一个 N*M 的棋盘上玩,每个格子有一个数.每次 选择两个相邻的格子,并使 ...
- CSS3教程链接
下面列出本站关于CSS3的相关链接,以方便大家阅读: 第一节:<CSS3 Gradient> 第二节:<CSS3 RGBA> 第三节:<CSS3 Border-radiu ...
- java读取文件多种方法
1.按字节读取文件内容2.按字符读取文件内容3.按行读取文件内容 4.随机读取文件内容 public class ReadFromFile { /** * 以字节为单位读取文件,常用 ...
- STORM_0010_Message passing implementation/消息传递的实现
下面是0.8.0之前的表述,之后的已经基于Disruptor改造过了 这个文章演示了发射和转移tuple是怎么在storm中工作的 Worker为消息传递负责 当zk中的任务出现了变化或者每个ta ...
- Codeforces Round #380 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 2) E. Subordinates 贪心
E. Subordinates time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...
- winscp 软件。
winscp 软件.是管理服务器的软件. 我们可以输入ip和password,对服务器上的代码进行管理.
- Jsoup模拟登陆例子
Jsoup模拟登陆小例子,不同的网站,需要不同的模拟策略,散仙在这里仅仅作为一个引导学习. package com.jsouplogin; import java.util.HashMap; impo ...