0%

C++中浅拷贝和深拷贝

C++中类的拷贝有两种:深拷贝,浅拷贝:当出现类的等号赋值(即:a=b)时,即会调用拷贝函数

深拷贝和浅拷贝的区别

  • 在未显示定义拷贝构造函数–(默认为浅拷贝),它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两个对象的数据成员中的指针变量将指向同一个地址。当其中一个对象结束调用时,调用析构函数,指针所指的内存被释放,但是此时另要给对象中的指针还指向那被释放的内存块,这就导致指针悬挂现象。

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:
- 通过使用另一个同类型的对象来初始化新创建的对象。
- 复制对象把它作为参数传递给函数。
- 复制对象,并从函数返回这个对象。
构造拷贝函数最常见的形式:

1
2
3
4
// https://www.runoob.com/cplusplus/cpp-copy-constructor.html
classname (const classname &obj) {
// 构造拷贝函数的主体
}
  • 深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据,从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。

应用场景

1
2
3
4
5
6
7
8
9
10
11
12
// 浅拷贝, 成员变量中没有动态分配的资源
class A {
public:
A(int _data) : data(_data){}
A(){}
private:
int data;
};
int main() {
A a(5);
b = a; // 仅仅是数据成员之间的赋值
}

假设我们成员变量中有指针指向堆(heap)的时候,因为堆的空间属于动态分配。若使用浅拷贝,则两个指针变量是指向同一块堆内存区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class A 
{
public:
A(int _size) : size(_size)
{
data = new int[size];
} // 假如其中有一段动态分配的内存
A(){};
~A()
{
delete [] data;
} // 析构时释放资源
private:
int* data;
int size;
}
int main()
{
A a(5), b = a; // 注意这一句
/*
b.size = a.size;
b.data = a.data; // 注意这里,就会出现上面这种情况。
*/
}

这时候就需要深拷贝

1
2
3
A(const A& _A) : size(_A.size){
data = new int[size];
} // 深拷贝

new和不用new创建类对象区别

  • new创建的类对象需要指针接受,一处初始化,多处使用。对象使用完需delete销毁。
  • new创建类对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
1
2
3
4
ClassName* a = new ClassNet();
delete a // 需要显式调用delete删除a所指内存

ClassName a; //不用new, 直接使用类定义声明,由于是存储在栈中,使用完后不需要手动释放。
  • new对象指针可以作为函数返回值,函数形参。

实例###

关于深拷贝的使用,可以参考leetcode 138