4.8C++深复制/浅复制/写时复制

–了解–

1.复制构造函数(拷贝构造函数)
作用:用一个已经生成的对象来初始化另一个同类的对象。
一般形式

    类名(const 类名&obj) {
     			函数体   
     			}

e.g.

     class Point{
       public:
       Point(const Point& r):x(r.x), y(r.y){}
        	      			//复制构造函数
       }
  • 复制构造函数有且只有一个本类类型对象的引用形参,通常使用const限定。
  • 因为复制构造函数只是复制对象,没有必要改变传递来的对象的值。
  • 定义形式
  • 类名 对象名1(类对象1),对象名2(类对象2),……;
对象赋值 对象复制
先定义了对象,再(对已经存在的对象)进行赋值 从无到有地创建一个新对象,并使它与一个已存在对象相同

2.合成复制构造函数

  • 每个类必须有一个复制构造函数
  • 如果没有定义,编译器会自动合成一个,称为合成复制构造函数(synthesized copy constructor)
  • 操作:执行逐个成员初始化,将新对象初始化为原对象的副本。
  • “逐个成员”:每个非静态数据成员,依次复制到正创建的对象中。

成员类型->复制含义:

①内置类型成员直接复制其值;
②类类型使用该类的复制构造函数进行复制;
③数组->复制数组每个元素。

  • 复制初始化->复制构造函数(ptr1=ptr2)
  • 直接初始化->与实参匹配的构造函数

如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用常规的大括号的数组初值列表形式来初始化数组时,则使用复制构造函数来初始化每个元素。

复制构造函数作用:函数可以传递对象和返回对象,对象数组才能用初值列表的形式初始化。

(疑问:怎么用初值列表对对象数组进行初始化)

浅复制

4.8C++深复制/浅复制/写时复制
缺点:容易将同一分配空间delete两次

深复制

4.8C++深复制/浅复制/写时复制
自己定义复制构造函数->实现深复制

e.g.代码来源
4.8C++深复制/浅复制/写时复制

DEEP COPY

(文字描述来源自matrix)
1.写时复制(Copy-on-write): 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你。也就是拖延版的深拷贝。

写时复制(是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真的释放掉这块空间。当有的指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧的空间的引用计数减一,新分配的空间引用计数加一)

写时复制的好处是结合和浅拷贝深拷贝的优点,对只读对象,可以十分迅速的完成对象拷贝,对需要修改的对象,可以延迟到实际修改的时候才进行内存空间的申请,分摊了系统调用的时间。

完成一个栈类,栈的复制采用写时复制规则 注意内存回收

提示

下图是写时复制的示意图。

第一步:有对象s1, 指向一个内存空间 [3, 2, 1],该空间的计数器为1,表示只有一个对象指向该空间

第二步:s2 = s1, 此时s2和s1共同指向一个内存空间,采用浅拷贝规则,该空间计数器为2,表示有两个对象指向该空间

第三步:当s1或s2需要改变数据时(比如,s2出栈),那么改变数据的对象进行深拷贝后再执行改变数据操作

当内存空间计数器 1->0 时,需要对该内存空间进行回收

4.8C++深复制/浅复制/写时复制