一.概念
用一个已经存在的对象去初始另一个新对象;拷贝构造函数是类中默认成员函数之一,它只有单个形参,且形参是本类类型对象的引用(一般用const修饰,不能改变已存在的类),在用已知类创建对象时,编译器会自动调用拷贝构造函数。( 关于默认成员函数)
拷贝构造函数是构造函数的一个重载形式,它一定是用来初始化一个新对象的,这区别于赋值重载函数 (将一个对象的值赋值给另一个已经存在的对象);
二.特征
1.关于构造函数,还有一点需要我们注意:拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。
当我们初始化d2时,需要调用拷贝构造函数将d1的值拷贝给d2,如果函数参数是按值传递,那么在函数调用时,又会使用拷贝构造函数创建实参d1的副本作为形参。
就会出现这样一种情况,无限次的调用拷贝构造函数。所以,拷贝构造函数的形参必须是引用。(按值传递时:自定义类型的传参需要调用拷贝构造函数去制造一个副本)
2.浅拷贝:
默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
那编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
由于是按照字节进行的浅拷贝,a和a2中的_a成员变量指向了同一块空间;
当一个对象中成员变量改变时,另一个也会随之改变;同时,当调用析构函数时,a2调用析构后,a1对已经销毁的空间仍然要进行一次释放,这时肯定会造成程序崩溃。(注:先定义的a1在析构是会后释放a1,类似于栈)
所以,当我们自己完成拷贝构造时,会额外开一块新的空间,仅仅对数据进行拷贝的操作叫作深拷贝。 类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则会引发程序崩溃。
注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。
三.应用
- 使用已存在对象创建新对象
- 函数参数类型为类类型对象(为提高效率,传参时尽量使用引用类型)
- 函数返回值类型为类类型对象(返回时也是能用引用就用引用,避免拷贝)
四.写时拷贝
写时拷贝(Copy - On - Write,COW):只有在真正需要修改数据时,才进行数据的拷贝操作,在此之前多个对象可以共享同一份数据(先使用浅拷贝,再需要修改时额外开空间-深拷贝)。
- 写时拷贝是一种优化策略,旨在减少不必要的数据拷贝,从而提高程序的性能和资源利用率。它通常用于管理动态分配的资源,如字符串、容器等。