【C++】五分钟带你搞懂深浅拷贝

目录

拷贝函数

浅拷贝拷贝构造函数

深拷贝拷贝构造函数

总结


前言

前面我们学习了C++的一些基本的知识点,并且介绍了一些STL里面String的一些关键操作,除了这些博主还新开了一个专栏关于Linux的讲解(Linux专栏链接)大家可以关注一下,后面我会一点一点的更新的。大家坐稳扶好,要开车了!!!

拷贝函数

在我们了解深浅拷贝之前博主简单介绍一下什么是拷贝构造函数,这里只是简单的介绍一下(拷贝构造详细介绍)

是C++中的一个特殊成员函数,用于创建对象的副本。它的作用是通过使用已有对象的属性值来初始化新对象,实现对象的复制操作。通过定义拷贝构造函数,我们可以控制对象的拷贝过程,并确保正确处理含有指针或动态分配内存的类。

拷贝构造函数的定义形式如下:

cpp 复制代码
类名(const 类名& 对象名)
{
    // 构造函数的主体部分
    // 将对象的属性值拷贝到新对象
}

拷贝构造函数的特点:拷贝构造函数在C++中具有自动调用、形参类型为const引用、逐一复制对象成员、隐式调用与显式调用、需要自定义情况等特点。

浅拷贝拷贝构造函数

浅拷贝是指简单地将一个对象的数据成员的值复制到另一个对象中,这包括基本数据类型和指针。在浅拷贝中,指针只复制了地址,而没有复制指针指向的数据。

下面我用一个简单的代码,说明C++中浅拷贝和拷贝构造函数的概念:

cpp 复制代码
#include <iostream>

class MyClass {
public:
  int* data;

  // 默认构造函数
  MyClass() {
    data = new int(0);
    std::cout << "Default Constructor called" << std::endl;
  }

  // 拷贝构造函数
  MyClass(const MyClass& obj) {
    data = new int(*(obj.data));
    std::cout << "Copy Constructor called" << std::endl;
  }

  // 析构函数
  ~MyClass() {
    delete data;
    std::cout << "Destructor called" << std::endl;
  }
};

int main() {
  // 创建对象a
  MyClass a;
  *(a.data) = 10;

  // 使用拷贝构造函数创建对象b
  MyClass b(a);

  // 修改对象b的值
  *(b.data) = 20;

  // 输出结果
  std::cout << "a.data: " << *(a.data) << std::endl;
  std::cout << "b.data: " << *(b.data) << std::endl;

  return 0;
}

输出结果为:

cpp 复制代码
Default Constructor called
Copy Constructor called
a.data: 10
b.data: 20
Destructor called
Destructor called

在上面的代码中,我们定义了一个名为 MyClass 的类,其中包含一个 int 类型的指针成员 data 。在默认构造函数中,我们创建了一个 data 指针,并将其初始化为0。在拷贝构造函数中,我们通过复制源对象的 data 指针的值来创建一个新的 data 指针。

在 main 函数中,我们首先创建一个对象 a 并将其 data 值设置为10。然后,我们使用拷贝构造函数创建了另一个对象 b ,并将其 data 值设置为与 a 相同的值。最后,我们分别输出了 a.data 和 b.data 的值。

需要注意的是,在拷贝构造函数中,我们需要手动为指针成员分配内存,并复制源对象指针的值。这是因为默认的浅拷贝只会复制指针的值,而不会创建新的内存空间。这可能会导致指向相同内存地址的多个指针,当其中一个指针释放内存时,其他指针也将失去引用的内存 。因此,在处理包含指针成员的类时,通常需要实现拷贝构造函数,并进行深拷贝(复制指针指向的数据)。这样可以确保每个对象有一份独立的数据,避免潜在的内存管理问题。

深拷贝拷贝构造函数

深拷贝是指在拷贝构造函数中创建一个新的对象,并复制源对象的所有数据成员 (包括指针指向的数据)。这样每个对象都拥有独立的内存空间,修改一个对象不会影响其他对象。

下面我用一个简单的代码,说明 C++ 中深拷贝和拷贝构造函数:

cpp 复制代码
#include <iostream>
#include <cstring>

class MyClass {
public:
  char* data;

  // 默认构造函数
  MyClass() {
    data = new char[1];
    *data = '\0';
    std::cout << "Default Constructor called" << std::endl;
  }

  // 拷贝构造函数
  MyClass(const MyClass& obj) {
    data = new char[strlen(obj.data) + 1];
    strcpy(data, obj.data);
    std::cout << "Copy Constructor called" << std::endl;
  }

  // 析构函数
  ~MyClass() {
    delete[] data;
    std::cout << "Destructor called" << std::endl;
  }
};

int main() {
  // 创建对象a
  MyClass a;
  a.data = new char[5];
  strcpy(a.data, "Hello");

  // 使用拷贝构造函数创建对象b
  MyClass b(a);

  // 修改对象b的值
  delete[] b.data;
  b.data = new char[6];
  strcpy(b.data, "World");

  // 输出结果
  std::cout << "a.data: " << a.data << std::endl;
  std::cout << "b.data: " << b.data << std::endl;

  return 0;
}

输出结果为:

cpp 复制代码
Default Constructor called
Copy Constructor called
a.data: Hello
b.data: World
Destructor called
Destructor called

在上面的代码中,我们定义了一个名为 MyClass 的类,其中包含一个 char* 类型的指针成员 data 。在默认构造函数中,我们为 data 分配了一个字符指针,并将其初始化为空字符串。在拷贝构造函数中,我们先为 data 分配了足够的内存空间,然后使用 strcpy 函数复制源对象的字符串数据。

在 main 函数中,我们首先创建一个对象 a 并为其 data 成员分配了足够的内存空间,并将其值设置为 "Hello"。然后,我们使用拷贝构造函数创建了另一个对象 b ,并将其 data 成员的值设置为与 a 相同的值。最后,我们修改了 b 的 data 值,确保每个对象都有独立的数据。

需要注意的是,在拷贝构造函数中,我们需要手动为指针成员分配足够的内存空间,并复制源对象指针指向的数据。这样可以确保每个对象都有自己的独立副本。同时,在析构函数中,我们需要释放指针成员所占用的内存空间,避免内存泄漏。

深拷贝对于包含动态分配内存的对象非常重要,例如使用 new 或 malloc 分配的内存。通过实现深拷贝的拷贝构造函数,可以保证每个对象有独立的内存空间,避免潜在的内存管理问题,提高程序的稳定性和可靠性。

总结

本篇文章主要讨论拷贝函数的概念和使用方法。文章中涵盖了浅拷贝和深拷贝两种拷贝构造函数的介绍。

拷贝函数:拷贝函数的概念和作用。浅拷贝拷贝构造函数,解释了浅拷贝的概念,即简单地将一个对象的数据成员的值复制到另一个对象中,详细介绍了浅拷贝的拷贝构造函数的实现,提供了一个示例,展示了如何使用浅拷贝拷贝构造函数。深拷贝拷贝构造函数,解释了深拷贝的概念,即在拷贝构造函数中创建一个新的对象,并复制源对象的所有数据成员(包括指针指向的数据),详细介绍了深拷贝的拷贝构造函数的实现,提供了一个示例,展示了如何使用深拷贝拷贝构造函数。

温馨提示

感谢您对博主文章的关注与支持!在阅读本篇文章的同时,我们想提醒您留下您宝贵的意见和反馈。如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

相关推荐
starzy19904 小时前
深入理解Scala隐式值:编译期自动装配
开发语言·后端·scala
布莱克6054 小时前
Swift 条件语句详解:从 if 到 switch 的完整指南
开发语言·ssh·swift·switch·条件语句·guard·if
汉克老师4 小时前
《从C++小白到算法高手:GESP 1—8级成长地图》第一讲:认识GESP——从编程新手到算法探索者
c++·gesp·信息学竞赛·小学生学c++
吴可可1234 小时前
ActiveX调用WScript.Shell原理揭秘
开发语言
晴天的雨.9925 小时前
【C++】继承篇
java·开发语言·c++
SomeOtherTime5 小时前
第 1 讲:内存布局与所有权解剖——栈帧、胖指针与“移动/拷贝”在汇编层面的真实面目
java·开发语言·汇编
青少儿编程课堂6 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会图形化考级:校园大富翁经营闯关解析
c++·python·算法·bfs·信息学竞赛
another heaven6 小时前
【C/C++ 第一次跨越(上):用 C++11/14 停止制造新的旧代码】
c语言·c++·制造
qq_406981036 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
总要学点什么6 小时前
第106篇:三维特效-流动线效果——让一颗光点沿整条线一路滚到头
开发语言·javascript·ecmascript·gis·webgl·材质·cesium