C++深复制和浅复制讲解

C++中的复制操作包含深复制和浅复制两种方式。简单来说,浅复制只复制指针而不复制指针指向的内存空间,而深复制会复制指针和指针指向的内存空间。

一般情况下,我们需要使用深复制,以避免浅复制造成指针指向错误的情况。

深复制的实现方式

在C++中,可以通过使用拷贝构造函数和赋值操作符实现深复制。

拷贝构造函数

拷贝构造函数是一种特殊的构造函数,用于在创建对象时,用已存在的对象来初始化新创建的对象。在深复制时,需要在新的对象中重新分配空间,将原始对象的值复制到新的对象中。

以下是一个使用拷贝构造函数实现深复制的示例代码:

#include <iostream>

class MyString{
private:
    char *str;
    int len;
public:
    MyString(const char *s){
        len = strlen(s);
        str = new char[len+1];
        strcpy(str, s);
    }
    // 拷贝构造函数
    MyString(const MyString &src){
        len = src.len;
        str = new char[len+1];
        strcpy(str, src.str);
    }
    ~MyString(){
        delete[] str;
    }
    char* getString(){
        return str;
    }
};

int main(){
    MyString str1("Hello World!");
    std::cout << "str1: " << str1.getString() << std::endl;

    MyString str2 = str1; // 拷贝构造函数
    std::cout << "str2: " << str2.getString() << std::endl;

    return 0;
}

在以上示例中,我们通过拷贝构造函数实现了深复制。我们创建了一个MyString对象str1,并将其值设置为"Hello World!"。接着,我们通过MyString str2 = str1;语句创建了另一个MyString对象str2。C++编译器默认调用拷贝构造函数来进行对象的拷贝操作。在拷贝构造函数中,我们重新分配了内存空间,并将原始对象的值复制到了新的对象中。

赋值操作符

C++中的赋值操作符用于将一个对象的值赋给另一个对象。在深复制时,我们需要在新的对象中重新分配空间,并将原始对象的值复制到新的对象中。为了实现深复制,我们需要自定义赋值操作符,而不是仅仅使用编译器默认的赋值操作符。

以下是一个使用自定义赋值操作符实现深复制的示例代码:

#include <iostream>

class MyString{
private:
    char *str;
    int len;
public:
    MyString(const char *s){
        len = strlen(s);
        str = new char[len+1];
        strcpy(str, s);
    }
    MyString &operator=(const MyString &src){
        if (this == &src)  // 检查自我赋值情况
            return *this;

        delete [] str;    // 释放原有内存
        len = src.len;
        str = new char [len+1];
        strcpy(str, src.str);

        return *this;    // 返回对象的引用
    }
    ~MyString(){
        delete[] str;
    }
    char* getString(){
        return str;
    }
};

int main(){
    MyString str1("Hello World!");
    std::cout << "str1: " << str1.getString() << std::endl;

    MyString str2("Goodbye World!");
    std::cout << "str2: " << str2.getString() << std::endl;

    str2 = str1; // 赋值操作符
    std::cout << "str2: " << str2.getString() << std::endl;

    return 0;
}

在以上示例中,我们定义了一个MyString类的赋值操作符,用于实现深复制。该赋值操作符使用了与拷贝构造函数相同的实现方式,重新分配了内存空间,并将原始对象的值复制到新的对象中。和拷贝构造函数一样,我们不能忘记在对象生命周期结束时释放所占用的内存,否则可能会导致内存泄漏或其他不可预测的行为。

浅复制的实现方式

浅复制只复制指针,而不复制指针所指向的内存空间。由于浅复制没有重新分配内存,当原始对象和新对象都指向同一块内存空间时,就可能出现指向错误的情况。通常情况下,我们不想使用浅复制。然而,在某些情况下,浅复制可以作为一种优化手段来使用,例如,当我们操作大型数据类型时,使用浅复制可以减少操作的开销。

以下是一个使用浅复制实现的示例代码:

#include <iostream>

class MyIntArray{
private:
    int *array;
    int size;
public:
    MyIntArray(int s=0): size(s){
        array = new int[size];
    }
    MyIntArray(const MyIntArray &src){
        size = src.size;
        array = src.array; // 浅复制
    }
    ~MyIntArray(){
        delete [] array;
    }
    int& operator[](int i){
        return array[i];
    }
};

int main(){
    MyIntArray arr1(5);
    arr1[0] = 1;
    arr1[1] = 2;
    arr1[2] = 3;
    arr1[3] = 4;
    arr1[4] = 5;

    MyIntArray arr2 = arr1; // 浅复制
    arr2[4] = 10;

    std::cout << "arr1[4]: " << arr1[4] << std::endl;
    std::cout << "arr2[4]: " << arr2[4] << std::endl;

    return 0;
}

在以上示例中,我们定义了一个MyIntArray类,该类包含一个整型数组和大小。我们在构造函数中分配了内存空间来存储整型数组。在拷贝构造函数中,我们使用了浅复制来实现复制对象的操作。在上面示例中,我们创建了一个MyIntArray对象arr1,将其大小设置为5,并分配内存空间来存储5个整数。接着,我们将arr1的前四个元素分别设置为"1"、"2"、"3"、"4",最后一个元素设置为"5"。之后,我们创建了另一个MyIntArray对象arr2,将其初始化为arr1的一个副本。当我们修改arr2的最后一个元素时,arr1的最后一个元素也会被修改。这是因为浅复制只复制了指针,arr1arr2指向的是同一块内存空间。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++深复制和浅复制讲解 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • qq2440启动linux后插入u盘出现usb 1-1: device descriptor read/64, error -110,usb 1

    针对“qq2440启动linux后插入u盘出现usb 1-1: device descriptor read/64, error -110,usb 1”的问题,我们可以尝试以下几个步骤进行排查和解决: 1. 检查硬件连接 首先,我们需要确定u盘插入是否有松动或接触不良等硬件问题。可以将u盘重新插拔几次并检查连接是否紧密。如果问题仍然存在,可以考虑更换其他的u…

    C 2023年5月24日
    00
  • C语言用指针支持队列

    为了使用指针来支持队列,我们需要定义一个结构体来表示队列。该结构体至少需要包括两个指针分别指向队列的头和尾,以及队列的大小。以下是一个示例: struct queue { int *data; // 存储队列元素的数据 int front; // 队列头 int rear; // 队列尾 int size; // 队列大小 }; 接下来,我们可以使用以下函数…

    C 2023年5月9日
    00
  • 浅谈C++中各种不同意义的new和delete的使用

    浅谈C++中各种不同意义的new和delete的使用 new和delete的基础用法 在C++中,我们可以使用new关键字来动态地为对象分配内存,使用delete关键字来释放该内存。通常的使用方式如下: int* p = new int; // 为一个int类型的数据分配内存空间并返回指向该内存的指针 *p = 10; // 对该内存空间进行赋值 delet…

    C 2023年5月22日
    00
  • windows下在vim中搭建c语言开发环境的详细过程

    一、安装vim 下载vim安装包:从vim官方网站(https://www.vim.org/download.php)下载适合你的操作系统版本的vim安装包,将其保存到本地。 安装vim:双击安装包进行安装,选择安装路径,并勾选”Add to PATH”选项,让vim能够在命令行中被调用。 验证安装:打开命令行窗口,输入”vim”命令,如果出现vim编辑器界…

    C 2023年5月23日
    00
  • C++实现简单学生信息管理系统

    以下是一份基本的“C++实现简单学生信息管理系统”的攻略: 步骤1:确定基本需求 在设计学生信息管理系统之前,我们应该先确定需要什么功能。这是你应该问自己的问题: 是一个控制台程序还是有图形化界面? 需要记录哪些学生信息(例如姓名、年龄、性别、学号、课程等级、分数)? 可以输入、输出和编辑吗? 是否可以按照特定的标准对学生进行排序和筛选? 可以进行计算吗,例…

    C 2023年5月23日
    00
  • 常用排序算法的C语言版实现示例整理

    最近我整理了一篇关于常用排序算法的C语言版实现示例的攻略,让大家可以更好地掌握这些算法的原理和实现方法。以下是该攻略的详细讲解。 1. 简介 本攻略主要介绍了常用排序算法的C语言版实现示例。常用的排序算法包括:冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序、归并排序、计数排序、桶排序和基数排序等。在C语言中,可以使用数组实现排序算法。 2. 排序算…

    C 2023年5月22日
    00
  • C++中map和vector作形参时如何给定默认参数?

    C++中,map和vector是常用的STL容器之一,它们通常被用作函数的参数,但是有时候我们需要为这些参数设置默认值。本文将详细讲解C++中map和vector作为形参时如何给定默认参数的方法。 map作为形参时如何给定默认参数 为了设置map的默认参数,我们需要在函数声明中使用“=”运算符来给map参数设置默认值。下面是一个使用map的函数,并设置默认参…

    C 2023年5月23日
    00
  • C++实现简单迷宫游戏

    C++实现简单迷宫游戏攻略 介绍 迷宫游戏是一种很有趣的益智游戏,在这个游戏中,玩家需要解决迷宫中的难题,找到通往出口的路线。本攻略将提供一个简单的迷宫游戏实现过程,使用 C++ 编程语言实现。 在这个项目中,我们将学习如何使用类、条件语句、循环和数组等 C++ 编程语言的基本语法和概念。在游戏中,我们将使用控制台窗口来创建一个命令行界面,玩家可以通过键盘操…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部