C++拷贝构造函数总结
目录:
- 拷贝构造函数的基础知识
- 拷贝构造函数的使用
- 拷贝构造函数的行为
1.拷贝构造函数的基础知识
拷贝构造函数(copy constructor)是构造函数,是拷贝已经存在的对象来创建一个新的对象。此方法的声明形式:object(const object&)。
例如:
class Object
{
Object(const Object &);
};
注意:参数的传递是引用传递的。因为如果在此处使用值传递,会造成递归引用。
2.拷贝构造函数的使用
拷贝构造函数在什么时候被使用,有助于我们了解拷贝构造函数的用途。一般而言,拷贝构造函数会在以下三种情况下被使用:
- 当构造一个新的对象时
- 使用值传递来传递函数参数
- 函数的返回值
 
2.1.当构造一个新的对象时,例如:
1 class Object{…};
2 Object a;
3 Object b = a;// 此函数调用的是拷贝构造函数
4 Object c;
5 c = a;          // 此处调用的是"operator = “
2.2.使用值传递来传递函数参数,例如:
1 class Object{…};
2 int Function_A(Ojbect param);
3 Object a;
4 Function_A(a);//在调用Function_A的时候,在函数内部使用a的拷贝构造函数来获取a的副本来进行函数的处理。
2.3.函数的返回值,例如:

1  class Object{…};
2
3  Object GetObject()
4  {
5      Object a;
6       return a;
7  }

3.拷贝构造函数的行为
拷贝构造函数分为默认构造函数和用户自定义函数,在此主要由这两方面来说明:
a. 默认构造函数:
如果对象没有提供显式的拷贝构造函数,编译器在发现需要使用拷贝构造函数函数的时候,会生成一个来使用,而生成的拷贝构造函数会有trival和nontrival之分,区别在于对象是否应该被按位拷贝(bitwise copy semantics)。
首先说下按位拷贝,首先来看下下面的代码:

1 #incluude “word.h”
2
3 Word d(“abcd”);
4
5 void fun()
6 {
7 Word verb = d;
8 }

我们得知,verb是根据d来初始化的,但是如果无法看到Word的定义,我们无法知道Word的默认构造函数的行为。如果Word中的成员变量都是内建类型的,例如,Word的定义如下:

1 Class Word
2 {
3 public:
4 Word(const char *);
5 ~Word(){delete []m_pData;}
6 // …
7 private:
8 char *m_pData;
9 int m_iSize;
10 };

那么,Word的定义呈现了“default copy semantics”,verb的初始化直接按位拷贝,编译器不用生成默认构造函数。但是,如果Word的成员变量中有成员变量声明了显式的拷贝构造函数,那么编译器就需要合成构造函数来完成verb的初始化操作,例如:

1 #include<string>
2 Class Word
3 {
4 public:
5 Word(const char*);
6 ~Word(){delete []m_pData}
7 //…
8 private:
9 std::string m_strData;
10 int m_iSize;
11 };

在此情况下,我们知道string声明有显式的拷贝构造函数,编译器在初始化verb的时候,就需要合成一个拷贝构造函数来调用string的拷贝构造函数。在合成的拷贝构造函数中,整型,指针等nonclass member也都会被拷贝。
需要注意的是,在以下的四种情况是不需要进行按位拷贝的:
- class内部的成员变量声明有显式的拷贝构造函数(不论是定义者声明(例如string)还是编译器合成的(例如包含string的Word定义))。
- class的基类有显式的拷贝构造函数(无论是被声明的还是被合成的)。
- class中有虚函数,因为编译器需要为对象设置虚函数表,所以无法按位拷贝。
- class继承虚基类。
 
b.用户自定义拷贝构造函数
顾名思义,是用户自己定义的拷贝构造函数,编译器发现由用户定义的拷贝构造函数的时候,是不会生成拷贝构造函数的。即使用户声明的构造函数有错误。但是在使用自定义构造函数的时候需要注意几点:
1.注意深拷贝和浅拷贝,在前面的例子中不含string的Word的定义中,有一个char *的指针,如果不考虑深拷贝,直接按位赋值的话,会造成隐含的bug。
2.在构造函数中不要调用虚函数,因为在此时对象没有创建完成,不能保证调用到正确的函数,同时,也会引起其他的错误(例如,类内部的成员变量没有初始化完毕就是用)。
3.在拷贝构造函数中需要考虑异常的发生。
以上就是拷贝构造函数的总结。其中第2,3节的示例来自《深入了解C++对象模型》。
如果有不对的地方,请大家指正,谢谢。
yetuweiba
分布式追踪系统dapper
最近看了google的分布式追踪系统dapper的论文:http://static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/zh-CN//pubs/archive/36356.pdf,结合自己的理解描述下。
一、引子:
用户输入关键字后只要敲个回车键就能返回搜索结果(图1a),这样一个简单的过程可能涉及到上千个服务,可能需要上千个服务器协作完成。如图1b所示,user发了RequestX请求到达A,A通过rpc(远程过程调用,如thrift)调用B以及C,而C又需要通过rpc调用D以及E等等。
对user的一次请求,他迟迟未收到响应ReplyX,或者响应时间很慢,我们需要确认性能到底消耗在哪个环节,这个时候我们该怎么办呢?自然是分析我们的日志。
我们每个服务都会有请求日志,请求日志记录着一次调用所花费的时间,比如对A来说,记录着调用B所花费的时间以及调用C所花费的时间,同理C的请求日志记录着调用D以及E所花费的时间。对于互联网应用来说,各个服务比如B,同一时刻可能有成百上千次请求记录。
这种日志有个致命缺点---没有将这些记录与特定的请求关联一起。对于user的一条特定的请求RequestX,我们不知道B日志中哪条记录与之对应,也不知道C日志中哪条记录与之对应。。。总而言之,我们不能很具体的分析user的一次请求响应缓慢到底消耗在哪个环节。

二、 如何将各个服务日志的每一条记录与特定的请求关联在一起呢?
当前学术界和工业界有两种方法:
1)黑盒方法(black box)
日志还是一样的记录,只是通过机器学习的方法来关联记录与特定的请求。以一条特定请求RequestX为变量,通过黑盒(也就是机器学习的模型,比如回归分析)从A的日志中找出一条记录与之对应,同理可以找出B、C、D、E等等的相关记录。
黑盒方法的优势就是不需要改变现有日志记录方法,但是缺点很明显,机器学习的精度往往不高,实际使用中效果不好。
2)基于注释的方案
利用应用程序或中间件给每条记录一个全局标志符,借此将一串请求关联起来。比如对RequestX来说,赋予一个标志符1000,后续相关各个服务都会将标识符1000与记录一起打在日志里。这种方法的优势就是比较精确,目前google、twitter、淘宝等都采用这种方式。下面介绍google的分布式追踪系统解决方案---dapper。
三、dapper的设计目标:
1)低消耗
dapper本质是用来发现性能消耗问题,如果dapper本身很消耗性能,没人愿意使用,因此低消耗是必须的,dapper使用一系列创新方法确保低消耗,比如使用采样方法。
2)应用级透明
应用级透明的意思是程序员可以不需要在自己的代码中嵌入dapper相关的代码就能达到分布式追踪日志记录的目的。每一个工程师都希望自己的代码是纯粹的,如果需要嵌入dapper相关代码,那么既影响代码维护,又影响bug定位。
3)扩展性好
对于一个快速发展的互联网公司而言,用户规模快速增长导致着服务以及机器数量越来越多,因此dapper需要适应相应的发展,扩展性要好。
四、dapper的几个关键点:
1)dapper日志记录的格式是怎样的呢?
dapper用span来表示一个服务调用开始和结束的时间,也就是时间区间(图2对应着图1b的调用图)。dapper记录了span的名称以及每个span的ID和父ID,如果一个span没有父ID被称之为root span。所有的span都挂在一个特定得追踪上,共用一个跟踪ID,这些ID用全局64位整数标示,也就是图2的traceID。

2)如何实现应用级透明?
在google的环境中,所有的应用程序使用相同的线程模型、控制流和RPC系统,既然不能让工程师写代码记录日志,那么就只能让这些线程模型、控制流和RPC系统来自动帮助工程师记录日志了。
举个例子,几乎所有的google进程间通信是建立在一个用C++和JAVA开发的RPC框架上,dapper把跟踪植入这个框架,span的ID和跟踪的ID会从客户端发送到服务端,这样工程师也就不需要关心。
3)dapper跟踪收集的流程
如图3所示,分为3个阶段:a)各个服务将span数据写到本机日志上;b)dapper守护进程进行拉取,将数据读到dapper收集器里;c)dapper收集器将结果写到bigtable中,一次跟踪被记录为一行。
 
 
4)如何尽可能降低开销?
作为一个分布式追踪系统,dapper希望尽可能降低性能开销。如果对每一次的请求都进行追踪收集,开销还是有点大的。一个比较好的方式是通过统计采样的方法,抽样追踪一些请求,从而达到性能开销与精度的折中。
dapper的第一个版本设置了一个统一的采样率1/1024,也就是1024个请求才追踪一次。后来发现对一些高吞吐的服务来说是可以的,比如每秒几十万的请求,但是对一些低吞吐量的服务,比如每秒几十个请求的服务,如果采样率设置为1/1024,很多性能问题可能不会被追踪到。因此在第二版本dapper提供了自适应的采样率,在低吞吐量时候提高采样率,在高吞吐量时降低采样率。
上面的采样是在第一个阶段,此外在收集器将span数据写到bigtable时,还可以使用第二次采样,即不一定都将数据写入到bigtable中。
五、dapper的使用
1)监测新服务部署性能情况
对一个新服务,往往需要经过一段时间的观察,这时候可以使用dapper进行监测,从而发现存在的性能的问题;
2)推断服务间的依存关系
通过使用dapper,可以很清晰的表明一个服务依赖了哪些服务,以及一个服务影响到哪些服务,这样能促使我们在上线的时候能及时通知下游服务监控者重点观察。
...)
六、dapper的不足
1)某些时候缓冲一些请求,然后一次性操作会比较高效,比如I/O请求等。各个请求都有traceID,但是聚集之后只有一个请求,因此只能选择一个traceID用于传递到聚集请求,这时追踪会中断。
2)dapper可能找出某个环节慢了,但不一定能找出根源。比如一个请求慢可能不是它自身慢,而可能它在消息队列中比较靠后。
...)
C++拷贝构造函数总结的更多相关文章
- C++ 拷贝构造函数和赋值运算符
		本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ... 
- C++ 一个例子彻底搞清楚拷贝构造函数和赋值运算符重载的区别
		class TestChild { public: TestChild() { x=; y=; printf("TestChild: Constructor be called!\n&quo ... 
- C++ 为什么拷贝构造函数参数必须为引用?赋值构造函数参数也必须为引用吗?
		之前写拷贝构造函数的时候,以为参数为引用,不为值传递,仅仅是为了减少一次内存拷贝.然而今天看到一篇文章发现自己对拷贝构造的参数理解有误. 参数为引用,不为值传递是为了防止拷贝构造函数的无限递归,最终导 ... 
- C++拷贝构造函数
		拷贝构造函数是一种特殊的构造函数,其定义为第一个参数为为本类型的一个引用或者是常引用,且无其它参数或者其它参数为默认值,例如下面的函数: X::X(const X&); X::X(X& ... 
- PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天
		PoEdu - C++阶段班[Po学校]- 第6天 课堂选择题目: 1 关于转换构造函数 ClassDemo demo = 1; 调用转换构造函数 2 关于拷贝赋值函数 demo =2; 首 ... 
- C++拷贝构造函数(深拷贝,浅拷贝)
		对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #i ... 
- C++ 拷贝构造函数 和 六大函数
		1. C++什么时候会调用 拷贝构造函数? a.一个对象作为函数参数,以值传递的方式传入函数体: b.一个对象作为函数返回值,以值传递的方式从函数返回:(实际使用时,会被编译器优化掉) c.一个对象 ... 
- 一个CString的实现 拷贝构造函数的应用
		class CString { public: CString (char* s); CString(); ~CString(); private: char *str; int len; stati ... 
- 【转】C++的拷贝构造函数深度解读,值得一看
		建议看原帖 地址:http://blog.csdn.net/lwbeyond/article/details/6202256 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很 ... 
- C++拷贝构造函数(深拷贝,浅拷贝)
		http://www.cnblogs.com/BlueTzar/articles/1223313.html 对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; ... 
随机推荐
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(8)-DbSession线程内唯一
			原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(8)-DbSession线程内唯一 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 ... 
- 如何学习ACM
			我想对未来的同学有几句话要说: 1 我们几乎没有noi上来的队员,大家只能依靠后期的更加刻苦的努力. 2 我们没有专业的班级或者机制形成职业ACM队伍,所以大家只能尽早的投入进来,用尽一切课余时间去训 ... 
- 关于”机器学习方法“,"深度学习方法"系列
			"机器学习/深度学习方法"系列,我本着开放与共享(open and share)的精神撰写,目的是让很多其它的人了解机器学习的概念,理解其原理,学会应用.如今网上各种技术类文章非常 ... 
- iOS10收集IDFA,植入第三方广告[终结]--ADMob
			[PS: 前段时间,公司做ASO推广,需要在应用中收集IDFA值,跟广告平台做交互!于是有了这个需求--] 1.首先,考虑了一下情况(自己懒 -_-#),就直接在首页上写了一个Banner,循环加载广 ... 
- 启用IIS7报错功能
			进入:控制面板 - 卸载程序 - 打开或关闭Windows功能 如果访问任何不存在页面或页面出错时空白: Internet 信息服务 - 万维网服务 - 常见 HTTP 功能 - HTTP 错误 打勾 ... 
- linux内核源码目录(转)
			Linux用来支持各种体系结构的源代码包含大约4500个C语言程序,存放在270个左右的子目录下,总共大约包含200万行代码,大概占用58MB磁盘空间. 源代码所有在目录:/usr/src/linux ... 
- 分析Cocos2d-x横版ACT手游源 2、server场景
			仍然一样 直接在代码 资源 下一个 上传 你可以看到自己 NFServerChangeLayer.h </pre><pre name="code" class=& ... 
- server正式的环境性能测试nginx-php 指着寻求突破的表现
			因为我是第三级城市语言.无法接触到更牛接触逼公司或环境.这是你母亲的现场环境摸过几次.截至完毕,测试已设法提高空间. 公司须要的站点执行环境.不能由于我这边的瓶颈而阻碍了公司进行,希望各位大能能不吝惜 ... 
- javascirpt怎样模仿块级作用域(js高程笔记)
			因为javascript没有块级作用域的概念,所以在块语句中定义的变量,实际上是在包括函数中而非语句中创建的. 如: function outputNumbers(count){ for(var i= ... 
- Java利用jcifs集成AD域用户认证
			近期一段时间发现AD这东西老火了,尤其是涉及到安全这一方面的,所以AD域用户认证成了如今网络安全方面的产品必备!这里就简单的分享一下,Java通过jcifs集成AD域用户实现认证,以实现网络安全! 我 ... 
