拷贝构造函数与深拷贝和浅拷贝

拷贝构造函数 浅拷贝 深拷贝 拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数常用于: 通过使用另一个同类型的对象来初始化新创建的对象; 复制对象把它作为参数传递给函数; 复制对象,并从函数返回这个对象。 那么拷贝构造函数 ... 阅读详情

拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量。 作用就是用来复制对象,在使用这个对象的实例来初始化这个对象的一个新的实例。类中可以存在多个拷贝构造函数。

拷贝构造函数的调用时机

  • 当函数的参数为类的对象时
#include<iostream>
using namespace std;
class CExample
{
private:
    int a;
public:
    CExample(int b)
    {
        a=b;
        printf("constructor is called\n");
    }
    CExample(const CExample & c)
    {
        a=c.a;
        printf("copy constructor is called\n");
    }
    ~CExample()
    {
     cout<<"destructor is called\n";
    }
    void Show()
    {
     cout<<a<<endl;
    }
};
void g_fun(CExample c)
{
    cout<<"g_func"<<endl;
}
int main()
{
    CExample A(100);
    CExample B=A;
    B.Show(); 
    g_fun(A);
    return 0;
}

调用g_fun()时,会产生以下几个重要步骤:
(1).A对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
(2).然后调用拷贝构造函数把A的值给C。 整个这两个步骤有点像:CExample C(A);
(3).等g_fun()执行完后, 析构掉 C 对象。

  • 函数的返回值是类的对象
#include<iostream>
using namespace std;
class CExample
{
private:
    int a;
public:
    //构造函数
    CExample(int b)
    {
     a=b;
        printf("constructor is called\n");
    }
    //拷贝构造函数
    CExample(const CExample & c)
    {
     a=c.a;
        printf("copy constructor is called\n");
    }
    //析构函数
    ~CExample()
    {
     cout<<"destructor is called\n";
    }
    void Show()
    {
     cout<<a<<endl;
    }
};
CExample g_fun()
{
    CExample temp(0);
    return temp;
}
int main()
{
    
    g_fun();
    return 0;
}

当g_Fun()函数执行到return时,会产生以下几个重要步骤:
(1). 先会产生一个临时变量,就叫XXXX吧。
(2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
(3). 在函数执行到最后先析构temp局部变量。
(4). 等g_fun()执行完后再析构掉XXXX对象。

  • 对象需要通过另外一个对象进行初始化


CExample A(100);
CExample B=A;


浅拷贝与深拷贝

拷贝者和被拷贝者若是同一个地址,则为浅拷贝,反之为深拷贝,深拷贝会在堆内存中另外申请空间来储存数据。默认的拷贝构造函数实现的是浅拷贝,数据成员中有指针时,必须要用深拷贝。

一般的赋值操作是深度拷贝:

//深度拷贝
int a = 5;
int b = a;

简单的指针指向,则是浅拷贝:

//浅拷贝
int a = 8;
int *p;
p = &a;

char* str1 = "HelloWorld";
char* str2 = str1;

如果要将上面的浅拷贝转换为深拷贝,需要这样

//深度拷贝
int a = 8;
int *p = new int;
*p = a;

char* str1 = "HelloWorld";
int len = strlen(str1);
char *str2 = new char[len];
memcpy(str2, str1, len);

以字符串拷贝为例,浅拷贝后,str1和str2同指向0x123456,不管哪一个指针,对该空间内容的修改都会影响另一个指针。
在这里插入图片描述
深拷贝后,str1和str2指向不同的内存空间,各自的空间的内容一样。因为空间不同,所以不管哪一个指针,对该空间内容的修改都不会影响另一个指针。
在这里插入图片描述
当出现类的等号赋值时,会调用拷贝函数,在未定义显示拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝,它能够完成成员的一一复制。当数据成员中没有指针时,浅拷贝是可行的。但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象。这时,必须采用深拷贝。

默认的拷贝构造函数存在弊端,看如下类定义

class TestCls{
public:
    int a;
    int *p;

public:
    TestCls()   //无参构造函数
    {
        std::cout<<"TestCls()"<<std::endl;
        p = new int;
    }

    ~TestCls()     //析构函数
    {
        delete p;   
        std::cout<<"~TestCls()"<<std::endl;
    }
};


int main(void)
{
    TestCls t1;
    TestCls t2 = t1;   //效果等同于TestCls t2(t1);

    return 0;
}

类的默认拷贝构造函数只会用被拷贝类的成员的值为拷贝类简单初始化,也就是说二者的p指针指向的内存空间是一致的。以前面TestCls可以知道,编译器为我们默认定义的拷贝构造函数为:

TestCls(const TestCls& testCls)
{
    a = testCls.a;
    p = testCls.p;      //两个类的p指针指向的地址一致。
}

main函数将要退出时,拷贝类t2的析构函数先得到执行,它把自身p指向的堆空间释放了;接下来,t1的析构函数得到调用,被拷贝类t1的析构函数得到调用,它同样要去析构自身的p指向指向的堆空间,但是该空间和t2类中p指向的空间一样,造成重复释放,程序运行崩溃。

解决办法十分简单,自定义拷贝构造函数,里面用深度拷贝的方式为拷贝类初始化:

class TestCls{
public:
    int a;
    int *p;

public:
    TestCls()
    {
        std::cout<<"TestCls()"<<std::endl;
        p = new int;
    }


    TestCls(const TestCls& testCls)
    {
        std::cout<<"TestCls(const TestCls& testCls)"<<std::endl;
        a = testCls.a;
        //p = testCls.p;
        p = new int;

        *p = *(testCls.p);      //为拷贝类的p指针分配空间,实现深度拷贝
    }

    ~TestCls()
    {
        delete p;   
        std::cout<<"~TestCls()"<<std::endl;
    }
};

int main(void)
{
    TestCls t1;
    TestCls t2 = t1;

    return 0;
}

防止默认拷贝发生

自定义拷贝构造函数,并设置为private属性,其实现体可以什么都不写,那么这个类将变成一个不可被复制的类了。

复制构造函数(深拷贝和浅拷贝) 复制构造函数介绍浅拷贝深拷贝 介绍 复制构造函数用于将一个对象复制到新对象中。它用于初始化过程中(包括按值传递函数),而不是常规的赋值过程中,类型如下: Class_name(const Class_name &); 它接受一个指向类对象的常量引用作为参数。对于复制构造函数,需要知道两点:何时调用和有和功能。 1.如何调用 创建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。有四种方式 Person ob; Person ob1(ob);//1 Person ob2=ob;//2 P 阅读详情

相关推荐

【UV打印机】PrintExp打印软件教程(六)-高级模式(马达)

输入高级模式密码进入高级模式高级模式界面有操作栏、控制栏、参数栏及参数界面操作栏名称功能说明文件加载数据从板卡加载参数保存将参数保存到主板退出退出高级模式固件导入固件导入配套版本下的固件配置*xpcfx导出固件导出当前使用的固件配置*xpcfx导入波形文件导入对应的波形文件*waf操作初始化系统继续初始化动作复位X轴复位回原点控制栏可进行小车运动、闪喷操作(此闪喷为点击进行闪喷,不受平台位置限制),无清洗功能。

Print World的专栏 3112

拷贝构造(深拷贝、浅拷贝)

简单理解一下深拷贝和浅拷贝

qq_42981122的博客 3676

逆向CarPlay协议时,除了USB主从切换,你还需要注意这3个关键点

本文深入探讨逆向CarPlay协议时的3个关键点,包括MFi协议背景、多通道协同工作机制和协议分析工具的高级过滤技巧。特别解析了USB主从切换后的复杂交互过程,帮助安全研究员和逆向工程师更好地理解CarPlay协议的核心机制与潜在安全研究切入点。

weixin_29164497的博客 381

深拷贝构造函数和浅拷贝构造函数

深拷贝构造函数和浅拷贝构造函数 拷贝构造函数有深拷贝构造函数和浅拷贝构造函数 分类:拷贝构造函数分为深拷贝构造函数和浅拷贝构造函数。 区别:浅拷贝,即只复制对象空间,不复制对象资源。 深拷贝,既复制对象空间又复制资源。 由C++语言提供的默认拷贝构造函数只是对对象进行浅拷贝逐个成员依次拷贝。 浅拷贝 深拷贝和浅拷贝只在z指针变量中才有的说法,指针对象要用深拷贝,可是其他变量就不用。 深拷贝 当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两

weixin_52045928的博客 469

(Linux)DHCP 超级作用域和中继代理(超难受做了超久)

DHCP服务器在192.168.159.0 可以实现分配IP的功能,现在要跨网段分配IP 就需要用到DHCP中继代理。中继代理有两张网卡分别eth0:IP 192.168.159.2 ;eth1: IP:192.168.200.2 。现在要实现192.168.200.0网段的客户机可以获取DHCP服务器的IP。中继代理其实是相当于一个路由器的作用 DHCP服务器的IP地址 :192.168.159...

DJ_joker的博客 2223

从零开始之stm32之CAN通信

CAN通信极简教程(小白友好版),从小白的视角了解并实现简单的STM32F103的CAN通信,直接上手。

qq_30993593的博客 1306

C++拷贝构造函数:深拷贝和浅拷贝

1 拷贝构造函数 它是一种特殊的构造函数,由编译器调用来完成一些基于同一类的其他对象的构件及初始化。 1.1 拷贝函数的调用场景: 1、值传递传递函数体 2、值传递从函数体返回(返回匿名对象) 3、用一个对象初始化另一个对象 1.2 举例说明 1、值传递传递函数体 #include <iostream> using namespace std; public: int a; Test(int x){ a=x; } Test(...

奔跑的小仙女 5480

SAP MRKO与MIRO的对比分析:为何寄售结算需要定制开发?

本文深入分析了SAP系统中MRKO与MIRO在寄售结算中的功能差异,揭示了标准MRKO在财务控制和业务流程上的局限性。通过定制开发实践,如BAdI增强和界面优化,企业可显著提升结算效率与准确性。文章还探讨了未来SAP S/4HANA在寄售结算中的智能化趋势,为相关企业提供技术参考。

weixin_29300241的博客 419

C++中拷贝构造函数的深拷贝和浅拷贝

什么是拷贝构造函数及拷贝构造函数的应用? 什么是拷贝构造函数 每个类都有6个默认成员函数(构造函数,析构函数,拷贝构造函数,赋值重载函数,取地址运算符重载函数,const修饰的取地址运算符重载函数) 也就是说即使你创建一个空类,也会存在这6个函数 其中构造函数只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰) 在用已存在的类类型对象创建新对象时由编译器自动调用 class sol...

weixin_44456232的博客 459

18、基于FSDD数据集的深度学习案例分析

本文基于FSDD(Free Spoken Digit Dataset)数据集,系统介绍了深度学习在语音数字识别中的应用。内容涵盖动态与静态计算图的对比、数据预处理流程(包括数据增强、固定长度处理和归一化)、监督学习与无监督学习的模型构建与训练过程,并通过实验对比了不同网络架构的性能。文中使用PyTorch实现2层全连接网络和自编码器模型,展示了正则化技术对提升模型准确率的关键作用。最后总结了关键技术并提出了实际应用建议,展望了未来在复杂模型、多模态融合和实时应用方向的发展潜力。

vscode6remote的博客 259

华为OD机试 - 音乐小说内容重复识别 - 并查集(Java 双机位C卷 200分)

华为OD机试 双机位C卷题库疯狂收录中,刷题。

学Java,找哪吒 159

【c++】拷贝构造函数中的深拷贝和浅拷贝

在这里我们将other的size给到新对象的size,通过std::copy将原对象other的数组内容完整复制到新分配的内存中。这行代码,本质是:把 other.data 指向的数组中,从起始位置到 size 个元素的所有数据,拷贝到 data 指向的内存地址开始的位置。综上所述,std::copy是比较通用且适配所有类型的,同时标准库有一定优化,其他都是按需选择。它只拷贝字节,对自定义对象中的指针,仅复制指针的地址值,不拷贝指针指向的内容,因此是浅拷贝;(或拷贝构造),就能实现真正的深拷贝;

2402_85646905的博客 722

PCL 点云格式转换【2024最新版】

常见点云格式转化汇总包括txt、stl、csv、ply、obj、xyz、las等。博客长期更新,本文最近一次更新时间为:2024年9月14日,代码更新至PCL1.14.1版本。

点云侠的博客 39万+

【C++拷贝构造函数、深拷贝和浅拷贝】

本文介绍了C++拷贝构造函数、深拷贝和浅拷贝的概念、语法以及实际应用场景。拷贝构造函数用于创建对象的副本,深拷贝和浅拷贝涉及到对象的内存管理方式。

武帝为此的博客 313

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

c++中 拷贝构造函数的深拷贝和浅拷贝--“浅拷贝”与“深拷贝”

C++中对象的复制就如同“克隆”,用一个已有的对象快速地复制出多个完全相同的对象。一般而言,以下三种情况都会使用到对象的复制: (1)建立一个新对象,并用另一个同类的已有对象对新对象进行初始化,例如: class Rect { private: int width; int height; }; Rect rect1; Rect rect2(rect1); // 使用rect1初始化r

chen 1881

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

拷贝构造函数(深拷贝和浅拷贝)

总结:当我们的类中的数据成员需要动态申请内存时,不能简单地去浅拷贝,这样会引起析构时,重复释放造成程序崩溃。所以若数据成员为指针并且要动态申请时我们需要自己写出构造函数,析构函数以及拷贝构造函数和赋值运算符重载。若不写拷贝构造函数,系统会默认生成一个浅拷贝的拷贝构造函数,,而函数成员是共用的(只有一份拷贝)。在建立对象时可用同一类 的另一个对象来初始化该对象的存储空间,这时所用的构造函数称为拷贝构造函数(Copy Constructor)。1.当将一个旧对象的内容去初始化一个新对象时,会调用拷贝构造函数。

记录C++/Linux/操作系统的学习 1067

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

C++ 深拷贝、浅拷贝和拷贝构造函数

浅拷贝:浅拷贝就是指不重新申请新的内存空间,仅仅是给原来被拷贝的量取了一个别名。这两名字都是共用的同一块内存空间。最典型的就是指针变量赋值。在通过一个指针修改了内存空间中的内容后,另外的指针也会发生相应改变。如下所示: #include <iostream> using namespace std; void test1() { int* p1 = new int(1); int* p2 = p1; cout << "*p1 = " <<

见牛羊的博客 421

C++中的拷贝构造函数(复制构造函数)以及涉及的深拷贝和浅拷贝问题

C++中的拷贝构造函数以及深浅拷贝。

m0_73968399的博客 2857

【C++学习笔记】拷贝构造函数以及深拷贝和浅拷贝

概念 拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用。其作用是使用一个已经存在的对象去初始化另一个同类的对象。 说明 1.在定义时通过等于号复制对象时,系统会自动调用拷贝构造函数。(注意,不是在任何时候等于号赋值都可以调用拷贝构造函数) 2.拷贝构造函数与原来构造函数实现了函数的重载。 (拷贝构造函数是构造函数的一个重载) 使用情景 一个对象作为函数参数,以值传递的方式传入函数体; ...

小浣熊的博客 1046

C++_复习04(拷贝构造函数的深拷贝和浅拷贝)

一、为什么会出现深拷贝和浅拷贝 在我们没有自定义拷贝构造函数的时候,传递对象给函数或者函数返回对象都能进行是因为C++编译器会给我们自动的产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅是使用“老对象”的值对“新对象”的数据成员依次进行赋值操作。 二、浅拷贝问题抛出 2.1 问题描述及代码 在不写拷贝构造函数的时候,使用C++编译器的默认拷贝构造函数运行...

郡酱的博客~ 228

C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字

1、在C++编码过程中,类的创建十分频繁。 简单的功能,当然不用考虑太多,但是从进一步深刻理解C++的内涵,类的结构和用法,编写更好的代码的角度去考虑,我们就需要用到标题所提到的这些内容。 最近,在看单例模式,觉得十分有趣,然而如果想要掌握单例模式,就必须掌握这些内容。下面是我的一些学习总结,参考了很多博客内容。文末将注明出处。 2、先上代码 // testSingleMode.cpp :

奋斗,永不止步 7774

拷贝构造函数,深拷贝和浅拷贝

1.什么是拷贝构造函数 当对象之间要直接赋值的时候,就会调用拷贝函数。如Test a,Test b=a;这就是对象之间的直接赋值。如果在类中并没有写拷贝构造函数,那么程序会自动调用一个默认的构造函数。如以下程序: 复杂一点这样说: 当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用

xxjoy_777的专栏 426

【C++】拷贝构造函数(深拷贝和浅拷贝)

而且,当实例c1的生命结束时,我们释放指针,而另一个实例c2没有释放,这时去使用它会导致不可预期的错误。同时,当程序离开两个myString所在的作用域,程序会按顺序调用两次析构函数,后执行的析构将释放一个不存在的内存空间,这也是一个未定义的行为。可以看到调用一次析构,析构的是this=0x7fffffffe368内存实例,而当函数出来时,两个实例的m_data指向的内存内容都没有了。改完之后的我就不进行GDB调试了,总之,当这样更改完之后,我们的拷贝构造就变成了深拷贝,避免了双重析构的问题。

meeiuliuus的博客 497

关于C++ 拷贝构造函数,深拷贝和浅拷贝的理解

对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=88; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 #include iostream> using namespace std; class CExample { private:      int a; pu

lj89168的专栏 761

笔试题 -- 拷贝构造函数 深拷贝和浅拷贝

C++拷贝构造函数(深拷贝,浅拷贝) 对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=88; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 #include using namespace std; class CExample { private:  int a; public:  CExample(int b)  { a=b;}  void Show ()  { cout<<a<<

xt18971492243的博客 324

拷贝构造函数,深拷贝和浅拷贝

拷贝构造函数和深拷贝,浅拷贝的举例:

hjhomw的博客 420
上一篇: ++i、i++、i+=1、i=i+1的区别
下一篇: C++中的字符串比较——字符数组、字符串(类)、字符指针
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值