C++的构造函数和析构函数(六)浅拷贝和深拷贝

浅拷贝

  • 编译器默认的提供的拷贝就是浅拷贝
    1、将一个对象的中的所有成员变量的值拷贝到另一个对象(上一篇博客)
    2、如果某个成员变量是个指针,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间
    3、可能会导致堆空间多次free的问题

深拷贝

  • 当类中有指针类型时,此时需要进行深拷贝,这时就要自定义拷贝构造函数
  • 将指针类型的成员所指向的内存空间拷贝到新的内存空间,也就是进行堆上的空间复制

浅拷贝程序分析

class Student {

	int m_age;
	char *m_name;

public:
	Student(int age, const char *name) {
		m_age = age;
		m_name = new char[100];
		strcpy(m_name, name);
	}

	~Student() {
		if (m_name != NULL) {
			delete[] m_name;
			m_name = NULL;
		}
		m_age = 0;
	}

	void Display() {
		cout << "age=" << m_age << ", name=" << m_name << endl;
	}
};

int main() {

	Student s1(18,"少爷");
	s1.Display();

	Student s2(s1);
	s2.Display();

	return 0;
}

运行结果

age=18, name=少爷
age=18, name=少爷

此时我们将析构函数注释掉,运行结果不变,但是当析构函数正常时,再次运行程序,就会出现运行错误

为什么会出现这这种情况呢?
分析

  • 对象s1调用了自定义的构造函数进行构造,但是由于我们没有给s2提供拷贝构造函数,这里会使用默认的拷贝构造函数,而默认的拷贝构造函数只对成员变量的值进行复制,所以s1和s2的值是一样的。复制后的内存结构如下所示

在这里插入图片描述
此时m_name的地址是一样的,他们所指向的是堆上的同一块地址空间,当程序运行结束后,会调用析构函数,此时会对堆上的这块空间释放两次(先释放s2,后释放s1),此时自然会出错!!!

解决方案:深拷贝

class Student {

	int m_age;
	char *m_name;

public:
	Student(int age, const char *name) {
		m_age = age;
		m_name = new char[100];
		strcpy(m_name, name);
	}
	
	//在上面的代码中加了拷贝构造函数
	Student(const Student& stu) {
		m_age = stu.m_age;
		m_name = new char[20];
		strcpy(m_name,stu.m_name);
	}

	~Student() {
		if (m_name != NULL) {
			delete[] m_name;
			m_name = NULL;
		}
		m_age = 0;
	}

	void Display() {
		cout << "age=" << m_age << ", name=" << m_name << endl;
	}
};

int main() {

	Student s1(18, "少爷");
	s1.Display();

	Student s2(s1);
	s2.Display();

	getchar();
	return 0;
}

内存使用情况如下图

在这里插入图片描述
此时对象s1和s2中的m_name 的地址不一样了,并且他们各自指向对上的一段空间,不会互相影响。(为了图方便,我没有标注的很详细,主要是为了对比上面一幅图)

总结
1、浅拷贝:地址拷贝
2、深拷贝:内容拷贝
3、什么时候需要考虑深拷贝:当类中成员有指针时

猜你喜欢

转载自blog.csdn.net/qq_47329614/article/details/106922715
今日推荐