C++:拷贝构造函数和拷贝赋值函数
本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。
拷贝构造函数
拷贝构造函数(复制构造函数)是构造函数的一种,它只有一个参数,参数类型是本类的引用。它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。
复制构造函数的参数可以是 const 引用,也可以是非 const 引用。 一般使用前者,这样既能以常量对象(初始化后值不能改变的对象)作为参数,也能以非常量对象作为参数去初始化其他对象。一个类中写两个复制构造函数,一个的参数是 const 引用,另一个的参数是非 const 引用,也是可以的。
如果类的设计者不写复制构造函数,编译器就会自动生成复制构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。编译器自动生成的复制构造函数称为“默认复制构造函数”。
默认构造函数(即无参构造函数)不一定存在,但是复制构造函数总是会存在。
|
|
执行结果:
constructor is called
copy constructor is called
100
destructor is called
destructor is called
拷贝构造函数的调用时机
1. 当函数的参数为类的对象:以值传递
的方式传入函数体
如果函数 F 的参数是类 A 的对象,那么当 F 被调用时,类 A 的复制构造函数将被调用。换句话说,作为形参的对象,是用复制构造函数初始化的,而且调用复制构造函数时的参数,就是调用函数时所给的实参。
|
|
执行结果:
constructor is called
copy constructor is called
100
copy constructor is called
g_func
destructor is called
destructor is called
destructor is called
调用g_fun()时,会产生以下几个重要步骤:
- A对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
- 然后调用拷贝构造函数把A的值给C。 整个这两个步骤有点像:CExample C(A);
- 等g_fun()执行完后, 析构掉 C 对象。
2. 函数的返回值是类的对象:以值传递
的方式从函数返回
如果函数的返冋值是类 A 的对象,则函数返冋时,类 A 的复制构造函数被调用。换言之,作为函数返回值的对象是用复制构造函数初始化 的,而调用复制构造函数时的实参,就是 return 语句所返回的对象。
|
|
运行结果:
constructor is called
copy constructor is called
destructor is called
copy constructor is called
destructor is called
10
destructor is called
当g_Fun()函数执行到return时,会产生以下几个重要步骤:
- 先会产生一个临时变量,就叫XXXX吧。
- 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
- 在函数执行到最后先析构temp局部变量。
- 等g_fun()执行完后再析构掉XXXX对象。
说明,由于g++ 编译是会进行优化,这里需要使用 : g++ -fno-elide-constructors xx 进行编译 C++返回值为对象时复制构造函数不执行怎么破 命名返回值优化
3. 对象需要通过另外一个对象进行初始化 : 赋值初始化
当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用。
注意:赋值语句的等号左边是一个早已有定义的变量,赋值语句不会引发复制构造函数的调用。
这条语句不会引发复制构造函数的调用,因为 c1 早已生成,已经初始化过了。
浅拷贝与深拷贝
1. 默认拷贝构造函数
很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:
当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象的复制问题,那就错了。
拷贝赋值函数
|
|
返回值的对象为引用是为了可以连续赋值
赋值函数中可以既可以使用引用也可以使用值传递,不过值传递会多生成一个对象,造成资源的浪费
1.对象以值传递方式从函数返回,且接受返回值的对象已经初始化过
2.对象直接赋值给另一个对象,且接受值的对象已经初始化过
copy constructor与copy assignment的区别与联系
- copy constructor:
从一个已有的对象来构造另一个对象;
包括:
用已有对象来初始化新声明的对象;
将对象按值传递给函数作为参数;
函数按值返回对象。
- copy assignment:
将已有的对象赋值个另一个已有的对象;
实例:
注意事项:编译器默认的copy constructor和copy assignment操作,是按照member-wise copy
的方式逐个copy每个member
,这种浅拷贝操作在有些情况下可能造成资源泄漏/指向重叠。
如果的确需要deep copy,需要自定义相应操作。这时需要清楚哪些地方用了copy constructor,哪些地方用了copy assignment,从而分别自定义copy constructor和copy assignment。一般来说,自定义的copy constructor、destructor和copy assignment操作常常同时出现。
区别与联系:
copy constructor不用检测是否是用一个对象来初始化它自己;
copy constructor不用对被构造对象做资源清理操作,如delete操作;