首页 > 编程语言 >C++浅拷贝与深拷贝

C++浅拷贝与深拷贝

时间:2022-11-03 13:24:08浏览次数:73  
标签:Name 函数 C++ Person 析构 拷贝 指针

目录

 

前言

一、区别

二、浅拷贝

1.简单描述

2.代码实例

三.深拷贝

1.简单描述

2.代码实例

 四.完整代码

五.运行结果

总结

 

 


前言

C++中有两种拷贝:深拷贝和浅拷贝

要是想要运用好拷贝函数就必须清楚深拷贝与浅拷贝的区别

一、区别

1  在未定义拷贝构造函数的情况下,系统会调用默认的拷贝函数——即浅拷贝(不用自己构造),它能够完成成员的简单的值的拷贝一一复制。当数据成员中没有指针时,浅拷贝是可行的;但当数据成员中有指针时,如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址(同一个堆区),当对象快结束时,会调用两次析构函数(析构函数也无需自己构造,但想要知道析构函数的工作可以自己构造析构函数用输出来记录),而导致指针悬挂现象,所以,此时,必须采用深拷贝。
2 深拷贝与浅拷贝的区别就在于深拷贝会在堆内存中另外申请空间来储存数据(新的堆区空间进行拷贝),从而也就解决了指针悬挂的问题。简而言之,当数据成员中有指针时,必须要用深拷贝。

 

二、浅拷贝

1.简单描述

       同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.

        一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。

 

 

2.代码实例

无自己构造的拷贝函数即无深拷贝构造函数:

析构函数是用来检验浅拷贝不能简单拷贝指针指向的堆区空间内容。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;
class Person
{
    public:
        Person()
        {}
        //初始化属性
        Person(const char* name, int age)
        {
            Name = (char*)malloc(strlen(name) + 1);
           
        } 
        //拷贝构造 系统会提供默认拷贝构造,而且是简单的值的拷贝即浅拷贝
        
        //析构调用
        ~Person()
        {
            cout << "析构函数的调用" << endl;
            if (Name != NULL)
            {
                free(Name);
                Name = NULL;
            }
        }
           
           
            //姓名
            char* Name;
            //年龄
            int Age;
       
};
void test01()
{
    Person p1("光头强", 10);
    Person p2(p1);//调用拷贝构造
}
        

int main(void)
{
    test01();
    system("pause");
    return 0;
}


  运行结果会崩掉,原因就是:系统会提供一个默认的简单值的拷贝即浅拷贝,实例代码中的p1.Age会被正常拷贝(浅拷贝),而指针p1对象中的*Name和(浅)拷贝p1后的p2中的*Name指向同一个堆区空间,因此析构函数会析构两回这个同一堆区空间而崩溃。p1对象中的Age进行拷贝是浅拷贝,p1对象中的指针*Name进行拷贝是深拷贝。
见下图:(指针指向同一堆区空间)
​编辑

 

三.深拷贝

1.简单描述

       当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间,深拷贝。

2.代码实例

上述示例代码加上拷贝构造函数即可实现深拷贝:

//增加拷贝构造函数  深拷贝
        Person(const Person& p)
        {
         Age = p.Age;
         Name = (char*)malloc(strlen(p.Name) + 1);//新建一个堆区空间
         strcpy(Name, p.Name);
        }

见下图:(深拷贝新建了一个堆区空间)

​编辑

运行结果是进行两次析构


 四.完整代码

 

深拷贝与浅拷贝的实现

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;
class Person
{
    public:
        Person()
        {}
        //初始化属性
        Person(const char* name, int age)
        {
            Name = (char*)malloc(strlen(name) + 1);
           
        } 
        //拷贝构造 系统会提供默认拷贝构造,而且是简单的值的拷贝即浅拷贝
        //增加拷贝构造函数
        Person(const Person& p)
        {
         Age = p.Age;
         Name = (char*)malloc(strlen(p.Name) + 1);
         strcpy(Name, p.Name);
        }
        //析构调用
        ~Person()
        {
            cout << "析构函数的调用" << endl;
            if (Name != NULL)
            {
                free(Name);
                Name = NULL;
            }
        }
           
           
            //姓名
            char* Name;
            //年龄
            int Age;
       
};
void test01()
{
    Person p1("光头强", 10);
    Person p2(p1);//调用拷贝构造
}
        

int main(void)
{
    test01();
    system("pause");
    return 0;
}


五.运行结果

​编辑

 

总结

深拷贝和浅拷贝的区别是在对象状态中包含其它对象的引用的时候,深拷贝的实现需要构造拷贝函数新建一个堆区空间在进行拷贝,浅拷贝直接拷贝即可(简单的值的拷贝)。

标签:Name,函数,C++,Person,析构,拷贝,指针
From: https://www.cnblogs.com/guang123/p/16854146.html

相关文章

  • C++ 反射机制
    前言反射的概念:指程序在运行时,访问、检测和修改它本身状态或行为的一种能力。wikipedia简单的来说,就是一种自描述和自控制的能力。如果联想到镜子,就可以很好的理解,你能通......
  • C/C++ 常识
    多态分为静态多态和动态多态1.静态多态:静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数就调用,没有的话就会发出警告或者......
  • 【c&c++】 cjson使用_Keil环境下Jansson解析库的使用——基于STM32F103
    前言之前我曾经写过几个JSON解析库的使用方法:Qt平台下使用QJson解析和构建JSON字符串使用cJSON库解析JSON使用cJSON库构建JSON对于嵌入式开发,比较常用的就是cJSON解析......
  • 转载文章 c++调用yolov4模型进行目标检测-使用yolov4官方接口
    前言yolo系列用c写的,在工程中的部署特别方便。4月份yolov4横空出世,之前试了试效果,精度确实有了很大的提升,AB大神nb。最近需要在C++项目中使用yolov4,尝试了opencv的调用(见......
  • 【c&c++】[C++]使用Jansson生成与解析json字符串
    安装配置序列化与反序列化生成Json解析JsonJansson是一个用于解码、编码、操控JSON的C库:简单直观的API和数据模型没有依赖项完整的Unicode支持(UTF-8)安装 ......
  • C++语法
    C++常量和变量变量的定义方式:const类型名字{};直接使用值#define名字值常量定义方式:类型名字{};类型名字=初始值;不管是常量还是变量,本质都是在内存中申......
  • 第十三届蓝桥杯省赛C++B组
    《X进制减法》题目连接:https://www.acwing.com/problem/content/4407/贪心,数学推导  我们先来看一下这个65是如何算出来的:321:第一位为二进制,则逢2进1,ans+=1;......
  • tensorflow1.x——如何在C++多线程中调用同一个session会话
    相关内容:tensorflow1.x——如何在python多线程中调用同一个session会话 =================================================......
  • C++ 常量引用,用来修饰形参,防止误操作
    voidfunc(constint&b){b=1000;//cout<<b<<endl;}intmain(){inta=10;//constint&b=10;//10是一个常量inta=10实际是c......
  • C++ 引用的本质就是一个指针常量
    //int*constb=&a;voidfunc(int&b){//*b=100b=100;}intmain(){inta=10;//int*constb=a;指针常量是指针方向......