C++内存分配和拷贝构造函数写研究
昨晚参加笔试,开错题,有印象中的概念,但目前尚不清楚是怎么回事,什么原理,导致错误的话题。现在总结。
一、C++写内存分配研究
问题考察例如以下,请先不要看答案,看看你是否能做对,呵呵:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG91cWQyMDEy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
怎么样。晕了没?正确答案及解析例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG91cWQyMDEy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
解析:char p[] = “...”是一个数组。这个数组是局部变量。char *p = “...”。是一个指针,这个指针指向一个字符串常量。差别在于:数组的话,字符串是存在这个数组里的,由于这个数组属于局部变量(存在栈区)。而当该函数运行完,位于栈区的局部变量就销毁了,就算把数组的地址返回给主函数。主函数也无法訪问到原有字符串了,应该输出乱码。可是,假设是指向字符串常量的指针,这个字符串是放在程序的常量区而不是放在局部变量中,那么把这个常量的地址返回给主函数,主函数也是能够訪问它的。
以下就针对C++中的内存分配做个总结:
一个C/C++编译的程序占用的内存分为下面几个部分:
1. 栈区(stack)
由编译器自己主动分配释放,存放函数地址、函数參数值、局部变量的值等。
2. 堆区(heap)
就是那些由new分配的内存块,他们的分配与释放由程序猿负责。一般一个new就要相应一个delete。假设程序猿没有释放掉,那么在程序结束后。操作系统会自己主动回收。
3. 全局/静态区(static)
全局变量和静态变量的存储是放在一块的,初始化的全局变量和初始化的静态变量在一块区域,为初始化的全局变量和未初始化的静态变量在相邻的还有一块区域。程序结束后由系统释放。
4. 常量存储区(const)
常量字符串就是放在这里的。
5. 程序代码区
存放函数体的二进制代码。
当中。堆栈的主要差别例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG91cWQyMDEy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" height="506" width="888">
爽歪歪了吧。以下就来看第二个问题吧。。
。
二、考察复制构造函数
问题描写叙述例如以下。问该程序的三种情况:A 程序编译错误。B 程序编译成功。执行时出现错误。C 程序正常执行,输出10。
答:A
解析:改题考察了复制构造函数的相关知识,在《C++ Primer》中解说了。复制构造函数的定义形式为:类名(const 类名 &变量名),即參数为类类型的引用。可是为什么非要必须这样定义呢?当然。const的意思很清楚,由于一般复制操作不希望改动实參中的值,因此我们用const来限定一下,当然这个const也能够去掉。即:A(A &other)。我们来分析一下引用的必要性:
1. 防止死循环的递归调用
复制构造函数会在下面情况下调用:
1) 一个对象以值传递的方式传入函数体;
2) 一个对象以值传递的方式从函数体返回。
3) 一个对象须要通过另外一个对象进行初始化。
因此,假设将复制构造函数定义为:A(A other),那么当我们使用A b = a;时,实际上相当于将a作为实參传递给other,而这样的情况下相当于1) 一个对象以值传递的方式传入函数体,又会触发复制构造函数的调用,而在调用时又会触发下一轮的复制构造函数的调用,关键的是採用这样的方式调用过程无法结束,会陷入死循环。因此,复制构造函数的形參必须是引用类型。
2. 高效率的引用
引用比較高效,传递引用能够避免复制(这也能够用来解释上一个原因)。假设一个数据对象相当的大。进行复制会浪费非常多时间,同一时候另一些类型是不支持复制的,像IO类就是不能够复制的。传递引用就能够避免这些问题了。
通过以上的讨论我们还能够引出浅拷贝与深拷贝的问题。
对于普通类型的对象来说,它们之间的拷贝非常easy,比如:int a = 10 ; int b = a ;可是对于类类型的对象,在某些情况下就要考虑特殊的问题。
浅拷贝:浅拷贝就是对象成员之间的简单赋值。比如,当你定义了一个类而没有提供它的复制构造函数,当时用该类的一个对象去给还有一个对象赋值时所运行的过程就是浅拷贝。
假设对象中没有其他的资源(如:堆、文件、系统资源等)。则深拷贝和浅拷贝没有什么差别,但当对象中有这些资源时,就必需要自己定义复制构造函数,来对这些对象进行合理的控制。
深拷贝:深拷贝指的是当拷贝对象中有其它资源(如堆、文件、系统等)的引用时(引用能够是指针或引用),对象得另开辟一块新的资源。而不再对拷贝对象中有对其它资源的引用的指针或引用进行单纯的赋值。如:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaG91cWQyMDEy/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
当我们通过例如以下使用它时:
int main()
{
B b = 10;
B c = b;
return 0;
}
假设未定义如上红色标注的复制拷贝函数,则是浅拷贝。它只进行简单的成员赋值。运行B c = b; 后c和b中的data都指向同一块内存区。当b运行析构时,它的data所指的内存区就被释放,而此时c的指针仍然指向那块区域。利用data指针再訪问或c析构时都会发生内存泄露或程序崩溃。加上红色标注部分即为深拷贝。在进行B c = b;时,c会又一次分配一份空间,并将值拷贝过来。此时B析构完之后。C仍然能够訪问。由于此时b和c指向的是两块不同的内存地址。
三、总结
通过上面的问题,发现自己对一些关键点理解的还是不够透彻。都知道它要考察啥,但是大脑里面知识结构太混乱,终于还是没有得出正确答案。《C++ Primer》然后,巩固一下吧。油!
!!
版权声明:本文博主原创文章。博客,未经同意不得转载。
C++内存分配和拷贝构造函数写研究的更多相关文章
- String类型_static成员_动态内存分配_拷贝构造函数_const关键字_友元函数与友元类
1:String类型 #include <iostream> using namespace std; int main() { //初始化方法 string s1 = "hel ...
- 漫步Facebook开源C++库Folly之string类设计(散列、字符串、向量、内存分配、位处理等,小部分是对现有标准库和Boost库功能上的补充,大部分都是基于性能的需求而“重新制造轮子”)
就在近日,Facebook宣布开源了内部使用的C++底层库,总称folly,包括散列.字符串.向量.内存分配.位处理等,以满足大规模高性能的需求. 这里是folly的github地址:https:// ...
- [C++参考]拷贝构造函数的参数必须是引用类型
在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识.在effective C++中说过这么一点:拷贝构造函数的参数必须是引用类型的.但是为什么呢? ...
- QVector的内存分配策略
我们都知道 STL std::vector 作为动态数组在所分配的内存被填满时.假设继续加入数据,std::vector 会另外申请一个大小当前容量两倍的区域(假设 n > size 则申请 n ...
- java基础(5)---内存分配
一.内存分配 如: 先写下面的源代码: 如果继续写:
- 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)
标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...
- S5PV210的内存分配研究分析
S5PV210内存一般会使用SDRAM和DDR2 (DDR SDRAM),SDRAM的uboot启动网络已经有很多资料的,对于DDR2还有有很多疑惑,如果有错误的地方,请大家一定指出,醍醐灌顶,不胜感 ...
- 内存的分配VS回收&构造函数VS析构函数
之前有一个问题一直困扰着我,就是一个变量出了作用域,我以为这个变量的内存就被回收了,其实不是这样的,昨天问了一个高手,才豁然开朗,自己在看相关代码的反汇编代码,才知道原来真是这样就.这个问题,我想简单 ...
- Com组件的内存分配和释放,CredentialProvider SHStrDup 字符串拷贝问题
一.简单介绍 熟悉CredentialProvider的同学应该知道,他为一个Com组件,于是,在这里的内存分配(字符串拷贝)的一系列操作就要依照con的标准来. 二.Com组件的内存分配和释放 CO ...
随机推荐
- C# Out和Ref区别
rel是有进有出,out是只出不进 ref 要求参数在传递给函数前要初始化,out则不需要
- 破解win2008r2服务器域用户名
启动PE系统 进入 cmd窗口 cd 进入 win2008r2服务器的安装盘(假设为d:) d: cd windows/system32 ren osk.exe osk02.exe #重命令屏幕键盘 ...
- 关与 Visual.Assist.X.V10.7.1912的Crack破解补丁(vs 番茄插件的key破解方法)
在win7系统下, 我用的是vs2012版本号. Visual Assist沿用了快10年的界面,最终有了更新,变得更加适合Win8 以及 VS2012的主题风格了 ,这也是以后软件的发展趋势,仅仅是 ...
- 从控制台读取password - C#
Tip : 从控制台读取password 语言: C# ______________________________________________________________ 在登陆Lin ...
- Android异步任务
本文主要探讨Android平台提供的各种异步载入机制,包括它们的适用场景.用法等. 1. AsynTask AsynTask适用于最长能够持续几秒钟的短时间的操作,对于长时间的操作,建议使用java. ...
- JSON.stringify 语法解释
行为:此函数的作用主要是串行化对象. 或许有些人是过敏的字系列.我非常理解easy.是对象的类型转换成字符串类型(或者更确切的说是json类型的).就这么简单.打个例如说,你有一个类,那么你能够通过这 ...
- ServletWeb缓存解决问题
(1)为什么我们要防止这个问题的浏览器页面缓存: 所以在不须要缓存的页面中须要实现不缓存页面. 代码例如以下: package com.lc.HttpTest; import java.io.IOEx ...
- 最少拦截系统(杭电1257)(DP)+(贪心)
最少拦截系统 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- VisualStudioOnline协同工作流程
VisualStudioOnline协同工作流程 项目负责人登陆自己的vsonline新建项目就不多说了. 直接从邀请队友开始 项目负责人操作 被邀请的邮箱必须是微软的邮箱(也就是可以登录visual ...
- Objective-C语言的一些基础特性
OC与C++.Java等面向对象语言有很多的类似之处,不过在很多方面也是有所差别的.若是用过某一种面向对象语言,那么就很容易理解OC语言所用的范式和模板了.但是在语法使用上,也许会显得陌生.因为OC语 ...