一.概念

 用一个已经存在的对象去初始另一个新对象;拷贝构造函数是类中默认成员函数之一,它只有单个形参,且形参是本类类型对象的引用(一般用const修饰,不能改变已存在的类),在用已知类创建对象时,编译器会自动调用拷贝构造函数。( 关于默认成员函数)

拷贝构造函数是构造函数的一个重载形式,它一定是用来初始化一个新对象的,这区别于赋值重载函数 (将一个对象的值赋值给另一个已经存在的对象);

二.特征

1.关于构造函数,还有一点需要我们注意:拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。

class Date
{
public:
		 Date(int year = 1900, int month = 1, int day = 1)
 		{
 			_year = year;
 			_month = month;
 			_day = day;
 		}
 // Date(const Date& d)   // 正确写法
 	   Date(const Date d)   // 错误写法:编译报错,会引发无穷递归
 		{
 			_year = d._year;
			_month = d._month;
		  _day = d._day;
 		}
private:
 			int _year;
			int _month;
		  int _day;
};
int main()
{
 Date d1;
 Date d2(d1);
 return 0;
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

当我们初始化d2时,需要调用拷贝构造函数将d1的值拷贝给d2,如果函数参数是按值传递,那么在函数调用时,又会使用拷贝构造函数创建实参d1的副本作为形参。c++拷贝构造函数_拷贝构造函数

就会出现这样一种情况,无限次的调用拷贝构造函数。所以,拷贝构造函数的形参必须是引用。(按值传递时:自定义类型的传参需要调用拷贝构造函数去制造一个副本)

     2.浅拷贝:

默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

那编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?

class A
{
public:
     A()
       :_size(10)
       , _a(new int(0))
     {}
   /* A(const A& a)
    {
        _a = new int;
        *_a = *(a._a);
        _size = a._size;
    }*/
    ~A()
    {
        delete _a;
        _size = 0;
    }
     int* _a;
     int _size;
};

int main()
{
    A a;
    A a2(a);
    *a._a = 7;
    std::cout<< *a2._a<<std::endl;//7
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

由于是按照字节进行的浅拷贝,a和a2中的_a成员变量指向了同一块空间;c++拷贝构造函数_拷贝构造函数_02

当一个对象中成员变量改变时,另一个也会随之改变;同时,当调用析构函数时,a2调用析构后,a1对已经销毁的空间仍然要进行一次释放,这时肯定会造成程序崩溃。(注:先定义的a1在析构是会后释放a1,类似于栈)

所以,当我们自己完成拷贝构造时,会额外开一块新的空间,仅仅对数据进行拷贝的操作叫作深拷贝。 类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则会引发程序崩溃。

注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

三.应用
  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象(为提高效率,传参时尽量使用引用类型)
  • 函数返回值类型为类类型对象(返回时也是能用引用就用引用,避免拷贝)
四.写时拷贝

写时拷贝(Copy - On - Write,COW):只有在真正需要修改数据时,才进行数据的拷贝操作,在此之前多个对象可以共享同一份数据(先使用浅拷贝,再需要修改时额外开空间-深拷贝)。

- 写时拷贝是一种优化策略,旨在减少不必要的数据拷贝,从而提高程序的性能和资源利用率。它通常用于管理动态分配的资源,如字符串、容器等。