c++ 入门之深入探讨拷贝函数和内存分配
在c++入门之深入探讨类的一些行为时,说明了拷贝函数即复制构造函数运用于如下场景:
- 对象作为函数的参数,以值传递的方式传给函数。
- 对象作为函数的返回值,以值的方式从函数返回
- 使用一个对象给另一个对象初始化
针对上述的三种情况,实际上很多时候,我们都会用到;如果我们采用系统默认的拷贝函数,程序容易发生我们无法掌控的错误。通常情况,我们会注意到:我们在定义一个拷贝函数的时候,往往会这么定义:classname(const classname& A),为什么一定要用引用类型传递参数呢?如果我们不采用引用类型,采用值传递:就陷入了问题的本身:我们试图定义自己的拷贝函数来解决值传递的过程中,调用拷贝函数的问题。假如我们的拷贝函数变量是值传递,那么当调用这个拷贝函数的时候,由于拷贝函数本身就是值传递,便使得再次调用拷贝函数,而一旦进行调用,又遇到值传递.....于是,陷入了死循环的过程。所以:拷贝函数一定要采用引用传递参数。
关于new和delete:用new生成的空间在堆区,而不是栈区。
我们关注一下这个事实:
class StringBad
{
private:
char *str;
int len;
static int num_strings; //= 0;//可见除了const 量之外,类内部成员是不能在内部赋初值的
public:
StringBad(const char * s);
StringBad();
~StringBad(); friend std::ostream & operator<<(std::ostream & os, const StringBad & st);
};
上面定义了一个类:关于这个类不再赘述类的一般特性。在此,我们仅仅关注这个点:char *str;即这个字符指针成员。如果我们定义了一个对象A,A.str = "hello world!".A.len = 10。假如,我们再定义一个对象B,B = A,那么,B.str = "hello world!",B.len = 10,这个也没什么问题。但问题在于:B.len 和A.len 变量的地址是不同的。B.str和A.str这两个指针自己的地址自然也是不同的,但他们却指向了同一个“"hello world!",也就是说,在定义B=A时,并没有将"hello world!"复制一遍,复制到另外一个内存空间,然后让B.str指向了这里。而是让B.str也指向了这个 "hello world!".即使得这个 "hello world!"看起来像一个公共资源!这实际上是十分危险的!!!假如我们变量B过期了,要被销毁,其指针变量指向的"hello world!"所在的内存被delete所回收,那么其实A.str这个时候指向的内存并不是“hello world”,而我们的本意是,让这些对象彼此独立,互不干扰,除非我们想这样(比如静态成员的存在)。
实际上,上述问题反映了一个重要的问题:深拷贝和浅拷贝。如果我们只是复制了地址,而没有赋值地址的内容,则是浅拷贝,否则为深拷贝。
总结:当我们在类中遇到指针成员时,务必要使得我们的拷贝函数成为深拷贝,而不是浅拷贝!!!(具体做法参考收藏的他人博文)
我们应该了解new ,delete 运作的本质:
char * p;
p = new char[];
上述描述了 p 首先是一个指针,然后通过new 开辟了10个char型空间,我们让p指向这个10个char型空间。
当对象被销毁时,会调用析构函数。析构函数中,应该包含:
delete[] p;
这表明了当这个对象被销毁后,与之关联的内存空间应该被销毁。delete[] p是什么含义呢?
delete并不是说我们销毁了p 这个变量,而是销毁了p指向的内存区。实际上P并不需要我们去销毁,因为p本身在栈区,而栈区的内存机制,我们是很清楚的。
我们再次强调:之所以我们要用delete来管理内存,是因为new分配的空间在堆区,堆区并不会随着对象的销毁而自行销毁,需要人为的对其销毁,new -delete就是“创建堆区空间”——“销毁堆区的机制”。但是作用域内的普通变量就不一样:他们生存在栈区,栈区的变量会随着作用域的变化,完成出栈,从而释放内存!
c++ 入门之深入探讨拷贝函数和内存分配的更多相关文章
- DLL函数中内存分配及释放的问题
DLL函数中内存分配及释放的问题 最近一直在写DLL,遇到了一些比较难缠的问题,不过目前基本都解决了.主要是一些内存分配引起问题,既有大家经常遇到的现象也有特殊的 情况,这里总结一下,做为资料. 错误 ...
- C++ 虚函数的内存分配
1.无继承的普通类: 在有虚函数的情况下类会为其增加一个隐藏的成员,虚函数表指针,指向一个虚函数表,虚函数表里面就是类的各个虚函数的地址了.那么,虚函数表指针是以什么模型加入到类里面的,虚函数表里 ...
- 数据结构和算法(Golang实现)(2)简单入门Golang-包、变量和函数
包.变量和函数 一.举个例子 现在我们来建立一个完整的程序main.go: // Golang程序入口的包名必须为 main package main // import "golang&q ...
- Python: 拷贝函数签名
使用场景有很多,比如C API在Python下很多都变成了(*args, **kwargs)的参数,这时候可能需要为其添加一个更严格签名来约束参数. 查了许多资料,能有效的拷贝函数签名貌似只能通过动态 ...
- 10-Python3从入门到实战—基础之函数
Python从入门到实战系列--目录 函数的定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数的语法 def 函数名(参数列表): 函数体 函数代码块以 def 关键词开头 ...
- c++不自动生成相关函数比如赋值、拷贝函数
默认情况下,如果没有明确声明某些函数比如赋值.拷贝函数,c++会自动生成这些函数,通常他们是对成员进行by-value拷贝,有些时候,赋值.拷贝对象并无什么意义或者不合理,比如对于socket或者th ...
- C++ 内存拷贝函数 memcpy
在C/C++中经常会遇到对一段固定的连续内存进行拷贝操作, 这时候我们就需要用到 <cstring> 头文件 中的 memcpy 函数. 具体使用如下: 其中 , ...
- c++中内存拷贝函数(C++ memcpy)详解
原型:void*memcpy(void*dest, const void*src,unsigned int count); 功能:由src所指内存区域复制count个字节到dest所指内存区域. 说明 ...
- C语言——常用标准输入输出函数 scanf(), printf(), gets(), puts(), getchar(), putchar(); 字符串拷贝函数 strcpy(), strncpy(), strchr(), strstr()函数用法特点
1 首先介绍几个常用到的转义符 (1) 换行符“\n”, ASCII值为10: (2) 回车符“\r”, ASCII值为13: (3) 水平制表符“\t”, ASCII值为 9 ...
随机推荐
- web前端(10)—— 浮动,清除默认样式
文档流 web页面和ps等设计软件有本质的区别,web 网页的制作,是个“流”,从上而下 ,像 “织毛衣”,就跟编程语言一样,都是由上而下 而设计软件 ,想往哪里画东西,就去哪里画 文档流带来的最明显 ...
- C#虚函数virtual详解
在面向对象编程中,有两种截然不同的继承方式:实现继承和接口继承.在实现继承时候,在Java中,所有函数默认都是virtual的,而在C#中所有函数并不默认为virtual的,但可以在基类中通过声明关键 ...
- Linux CPU占用率监控工具小结
关键词:top.perf.sar.ksar.mpstat.uptime.vmstat.pidstat.time.cpustat.munin.htop.glances.atop.nmon.pcp-gui ...
- 自动获取svn的版本号
需求 在做打包时,需要获取本地svn仓库的版本号,如下所示: 下面是我试过的几种做法 SubWCRev 使用SubWCRev.exe(TortoiseSVN自带的小工具),用法简单,但获取到的版本号有 ...
- PHP中判断变量是否存在的方式
isset()函数判断变量是否设置. thinkPHP中判断select查询时返回值是否为空 $object->isEmpty() empty():当变量存在,并且是一个非空非零的值时,返回 ...
- 当web应用包含了websocket长连接,如何在web应用前加一层nginx转发
1 通过在web应用的前面加一层nginx ,可以实现一台主机部署多个应用,每个应用都可以用不同的域名去访问,并且端口都是80 2 nignx 转发websocket长连接 1 每个web应用,他们运 ...
- 使用pkg打包Node.js应用的方法步骤
Node.js应用不需要经过编译过程,可以直接把源代码拷贝到部署机上执行,确实比C++.Java这类编译型应用部署方便.然而,Node.js应用执行需要有运行环境,意味着你需要先在部署机器上安装Nod ...
- 004_浅析Python的GIL和线程安全
在这里我们将介绍Python的GIL和线程安全,希望大家能从中理解Python里的GIL,以及GIL的前世今生. 对于Python的GIL和线程安全很多人不是很了解,通过本文,希望能让大家对Pytho ...
- Spring Security(二十六):8. Spring Security Community
8.1 Issue Tracking Spring Security uses JIRA to manage bug reports and enhancement requests. If you ...
- javascript之Map
javascript中的map,我用的不是特别多,倒是Java中的Map或HashMap,经常用. 顺便围绕几个方面介绍一下map? 1.Map对象 Map对象是一种有对应键值对的对象,JS的Obje ...