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 ...
随机推荐
- 盒子模型、网页自动居中、float浮动与清除、横向两列布局
1.CSS包含:标准文档流,浮动,绝对定位 标准文档流的特点:从上到下,从左到右,输出文档内容 盒子模型:块级元素(div ui li dl dt p)与行级元素(span strong img in ...
- IOS UIWebView用法
转自猫猫小屋 IOS webview控件使用简介(一) IOS webview控件使用简介(二)–加载本地html
- jvm程序执行慢诊断手册
生产环境最多的几种事故之一就是程序执行慢,如果是web服务的话,表现就是响应时间长.本文分享,从业多年形成的排查守则. 诊断步骤 系统资源查看 首先是系统资源查看,而且必须是在第一步.因为很多事故都是 ...
- SQL Server 一致性读
我们在Oracle和MySQL数据库中已经对一致性读的概念比较熟悉了,但是在SQL Server中却鲜少提及,但SQL Server自2005版本以来其实也实现了一致性读,几乎所有关系型数据库产品的一 ...
- SQL SERVER的锁机制
SQL SERVER的锁机制(一)——概述(锁的种类与范围) SQL SERVER的锁机制(二)——概述(锁的兼容性与可以锁定的资源) SQL SERVER的锁机制(三)——概述(锁与事务隔离级别) ...
- Linux安装Python3后,如何使用pip命令
系统环境:CentOS7.4 已安装好Python3.6.5 Python3.6.5自带pip 使用pip安装第三方库,可运行指令,例如安装paramiko库: python -m pip insta ...
- June 4. 2018 Week 23rd Monday
Don't criticize what you can't understand. 不懂的,不要随意批判. From Bob Dylan. Don't criticize what you can' ...
- 第一次使用Open Live Writer维护BlogJava
换了电脑,又重装了一堆东西,现在才把Open Live Writer整好.顺便记下几个心得: Open Live Writer已经没办法从网站上下载了,介绍个方法,可以把地址直接拷贝到迅雷里面,然后请 ...
- C# Lambda 表达式学习之(三):动态构建类似于 c => c.Age == null || c.Age > 18 的表达式
可能你还感兴趣: 1. C# Lambda 表达式学习之(一):得到一个类的字段(Field)或属性(Property)名,强类型得到 2. C# Lambda 表达式学习之(二):LambdaExp ...
- ScriptManager的几个属性和方法
ScriptManager的几个属性和方法 一.EnablePageMethods ScriptManager的EnablePageMethods属性用于设定客户端javascript直接调用服务 ...