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)
- 直接初始化->与实参匹配的构造函数
如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用常规的大括号的数组初值列表形式来初始化数组时,则使用复制构造函数来初始化每个元素。
复制构造函数作用:函数可以传递对象和返回对象,对象数组才能用初值列表的形式初始化。
(疑问:怎么用初值列表对对象数组进行初始化)
浅复制
缺点:容易将同一分配空间delete两次
深复制
自己定义复制构造函数->实现深复制
e.g.代码来源
DEEP COPY
(文字描述来源自matrix)
1.写时复制(Copy-on-write): 当你读取到这个空间的时候,并不会开辟出一个一模一样的空间出来给你,当你真正需要拷贝的时候,那么他就会开辟出空间给你。也就是拖延版的深拷贝。
写时复制(是通过"引用计数"实现的,在分配空间的时候多分配4个字节,用来记录有多少个指针指向块空间,当有新的指针指向这块空间时,引用计数加一,当要释放这块空间时,引用计数减一(假装释放),直到引用计数减为0时才真的释放掉这块空间。当有的指针要改变这块空间的值时,再为这个指针分配自己的空间(注意这时引用计数的变化,旧的空间的引用计数减一,新分配的空间引用计数加一)
写时复制的好处是结合和浅拷贝和深拷贝的优点,对只读对象,可以十分迅速的完成对象拷贝,对需要修改的对象,可以延迟到实际修改的时候才进行内存空间的申请,分摊了系统调用的时间。
完成一个栈类,栈的复制采用写时复制规则 注意内存回收
提示
下图是写时复制的示意图。
第一步:有对象s1, 指向一个内存空间 [3, 2, 1],该空间的计数器为1,表示只有一个对象指向该空间
第二步:s2 = s1, 此时s2和s1共同指向一个内存空间,采用浅拷贝规则,该空间计数器为2,表示有两个对象指向该空间
第三步:当s1或s2需要改变数据时(比如,s2出栈),那么改变数据的对象进行深拷贝后再执行改变数据操作
当内存空间计数器 1->0 时,需要对该内存空间进行回收