C++面试题之浅拷贝和深拷贝的区别「建议收藏」

C++面试题之浅拷贝和深拷贝的区别「建议收藏」先考虑一种情况,对一个已知对象进行拷贝,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。先看一个例子,有一个学生类,数据成员时学生的人数和名字:#include<iostream>usingnamespacestd;classStudent{private: intnum; c…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

       先考虑一种情况,对一个已知对象进行拷贝,编译系统会自动调用一种构造函数——拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数。

       先看一个例子,有一个学生类,数据成员时学生的人数和名字:

#include <iostream>  
using namespace std;

class Student
{
private:
	int num;
	char *name;
public:
	Student();
	~Student();
};

Student::Student()
{
	name = new char(20);
	cout << "Student" << endl;

}
Student::~Student()
{
	cout << "~Student " << (int)name << endl;
	delete name;
	name = NULL;
}

int main()
{
	{// 花括号让s1和s2变成局部对象,方便测试
		Student s1;
		Student s2(s1);// 复制对象
	}
	system("pause");
	return 0;
}

C++面试题之浅拷贝和深拷贝的区别「建议收藏」
       执行结果:调用一次构造函数,调用两次析构函数,两个对象的指针成员所指内存相同,这会导致什么问题呢?name指针被分配一次内存,但是程序结束时该内存却被释放了两次,会导致崩溃!

C++面试题之浅拷贝和深拷贝的区别「建议收藏」

 

       这是由于编译系统在我们没有自己定义拷贝构造函数时,会在拷贝对象时调用默认拷贝构造函数,进行的是浅拷贝!即对指针name拷贝后会出现两个指针指向同一个内存空间。

 

C++面试题之浅拷贝和深拷贝的区别「建议收藏」

       所以,在对含有指针成员的对象进行拷贝时,必须要自己定义拷贝构造函数,使拷贝后的对象指针成员有自己的内存空间,即进行深拷贝,这样就避免了内存泄漏发生。

        添加了自己定义拷贝构造函数的例子:

#include <iostream>  
using namespace std;

class Student
{
private:
	int num;
	char *name;
public:
	Student();
	~Student();
	Student(const Student &s);//拷贝构造函数,const防止对象被改变
};

Student::Student()
{
	name = new char(20);
	cout << "Student" << endl;

}
Student::~Student()
{
	cout << "~Student " << (int)name << endl;
	delete name;
	name = NULL;
}
Student::Student(const Student &s)
{
	name = new char(20);
	memcpy(name, s.name, strlen(s.name));
	cout << "copy Student" << endl;
}

int main()
{
	{// 花括号让s1和s2变成局部对象,方便测试
		Student s1;
		Student s2(s1);// 复制对象
	}
	system("pause");
	return 0;
}

C++面试题之浅拷贝和深拷贝的区别「建议收藏」
        执行结果:调用一次构造函数,一次自定义拷贝构造函数,两次析构函数。两个对象的指针成员所指内存不同。
 总结:浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。
再说几句:
当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应该考虑以下两种情形:
1.当函数的参数为对象时,实参传递给形参的实际上是实参的一个拷贝对象,系统自动通过拷贝构造函数实现;
2.当函数的返回值为一个对象时,该对象实际上是函数内对象的一个拷贝,用于返回函数调用处。

 

3.浅拷贝带来问题的本质在于析构函数释放多次堆内存,使用std::shared_ptr,可以完美解决这个问题。

 

关于std::shared_ptr的原理和实现可参考:C++笔试题之smart pointer的实现

一个完整的自定义类实现可参考:C++笔试题之String类的实现

 

参考链接:https://www.cnblogs.com/always-chang/p/6107437.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/186966.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 数据库设计概念结构设计_数据库设计典型实例

    数据库设计概念结构设计_数据库设计典型实例文章目录数据库设计概念设计结构概念结构设计ER模型的基本元素实体/实体集属性区别实体和属性联系二元联系的关系1:11:nm:n一元联系1:11:nm:n三元联系采用ER模型的概念设计设计局部ER模型例题设计全局ER模型全局ER模型的优化数据库设计数据库设计:构造最优的数据模型,建立数据库及其应用系统的过程数据库设计的好坏非常重要概念设计结构概念设计的目标是产生反映用户需求的数据库概念结构,即概念模型概念模型具有硬件独立、软件独立的特点处于一个桥梁作用概念设计的主要步骤

    2022年10月12日
  • 阿基里斯追乌龟的思考,空间,时间,速度非连续

    阿基里斯追乌龟的思考,空间,时间,速度非连续高中的时候才接触和了解,诺阿基里斯追乌龟的悖论,一直萦绕在自己的心头。在上大学的时候,学习了微积分,自己以为自己懂了,但是最近又思考的时候,发现大学里的那种想法还是存在着一些矛盾,自己没有意识到。再度思考,将自己的想法记录下来,如果存在问题,还请多多指教。按照积分将追逐的过程映射为无限级数的和,然后极限求解,但是极限本身就是一个无限接近但是不可到达的过程,因此在我看来…

    2022年6月18日
  • 格雷码与二进制的转换[通俗易懂]

    格雷码与二进制的转换[通俗易懂]一、什么是格雷码?格雷码,又叫循环二进制码或反射二进制码,格雷码是我们在工程中常会遇到的一种编码方式,它的基本的特点就是任意两个相邻的代码只有一位二进制数不同,这点在下面会详细讲解到。格雷码的基本特点就是任意两个相邻的代码只有一位二进制数不同,这点很重要。常用的二进制数与格雷码间的转换关系如下表:二、二进制格雷码与自然二进制码的互换1、二进制码转换成二进制格雷码  二进制码转换成二进制格雷码,

    2022年10月17日
  • 如何挖矿ETH_以太坊个人挖矿

    如何挖矿ETH_以太坊个人挖矿原文链接:https://zhuanlan.zhihu.com/p/32830672官方钱包以太坊的官方网站是:EthereumProject在网站页面的中间部分,提供了官方钱包的下载链接,网站会自动检测你的操作系统,并提供对应系统下钱包软件的下载链接。不过,官方钱包需要同步区块,既浪费时间,又占用硬盘空间。同时,官方钱包提供了大量其他的功能,比如智能合约。如果只是挖矿的话,这些多余的功能反倒增…

    2022年10月15日
  • 学习方法

    学习方法

    2021年8月17日
  • #从源头解决# 自定义头文件在VS上出现“无法打开源文件“XX.h“的问题

    #从源头解决# 自定义头文件在VS上出现“无法打开源文件“XX.h“的问题自己编写了一个头文件,在主函数中通过#include引用时出现了无法打开源文件的问题,通过网上查阅,发现是自己混淆了#include<>和#include””的用法。问题完美解决!…

    2022年6月16日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号