【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.datab.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 相同的值。最后,我们修改了 bdata 值,确保每个对象都有独立的数据。

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

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

总结

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

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

温馨提示

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

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

相关推荐
罗政几秒前
PDF书籍《手写调用链监控APM系统-Java版》第12章 结束
java·开发语言·pdf
匹马夕阳1 分钟前
详细对比JS中XMLHttpRequest和fetch的使用
开发语言·javascript·ecmascript
月巴月巴白勺合鸟月半2 分钟前
一个特别的串口通讯
开发语言·串口通讯
乄北城以北乀7 分钟前
第1章 R语言中的并行处理入门
开发语言·分布式·r语言
全栈老实人_17 分钟前
农家乐系统|Java|SSM|VUE| 前后端分离
java·开发语言·tomcat·maven
Tester_孙大壮32 分钟前
Python爬虫技术科普
开发语言·爬虫·python
点点滴滴的记录37 分钟前
Java的CompletableFuture实现原理
java·开发语言·javascript
程序猿online39 分钟前
nvm安装使用,控制node版本
开发语言·前端·学习
一只傻小白,42 分钟前
JAVA项目中freemarker静态模板技术
java·开发语言
机跃44 分钟前
递归算法常见问题(Java)
java·开发语言·算法