C++之浅拷贝、深拷贝、拷贝构造函数、拷贝赋值运算符、自定义的深拷贝函数应用总结(二百二十九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:理解C++之拷贝类对象到this指针应用。

  1. 浅拷贝(Shallow Copy):
    浅拷贝是指简单地复制对象的成员变量的值。在浅拷贝中,只复制指针或基本数据类型的值,而不会创建新的动态内存或复制指针所指向的数据。这导致多个对象共享相同的内存,可能引发潜在的问题,例如内存释放或修改数据时的冲突。

  2. 深拷贝(Deep Copy):
    深拷贝是指复制整个对象及其动态分配的内存。在深拷贝中,会创建一个新的对象,并为新对象的成员变量分配独立的内存,以复制原始对象的数据。这样可以确保每个对象拥有独立的内存空间,从而避免了共享数据的问题。

  3. 拷贝构造函数(Copy Constructor):
    拷贝构造函数是类的特殊成员函数,用于创建一个新对象,该新对象是通过复制现有对象的数据来初始化的。拷贝构造函数通常以引用形式接受一个同类型的对象作为参数,并从参数对象中复制数据到新对象。拷贝构造函数常用于对象的初始化、传递对象给函数或返回对象时进行复制操作。

  4. 拷贝赋值运算符(Copy Assignment Operator):
    拷贝赋值运算符是另一个特殊成员函数,用于将一个对象的数据复制给另一个已存在的对象。通常以赋值运算符(=)表示,并在函数体内执行适当的数据复制操作。拷贝赋值运算符允许对象之间完成数据的拷贝和替换,使一个对象能够取代另一个对象的数据。

  5. 自定义的深拷贝函数(Custom Deep Copy Function):
    自定义的深拷贝函数是用户自行编写的函数,用于实现对于类对象的深度复制。这种函数通常通过自己分配新的内存,并复制原始对象的成员变量内容到新分配的内存中。自定义的深拷贝函数可以在没有默认的拷贝构造函数或拷贝赋值运算符的情况下,实现深度复制。

  6. 通过指针进行拷贝(Copy by Pointer):
    通过指针进行拷贝是一种在类的拷贝操作中,复制指针本身的值,而不是复制指针指向的数据。这意味着多个指针将指向相同的数据,从而可能导致数据修改引起的冲突。这种方式通常不是推荐的拷贝方式,除非确保指向的数据不会在拷贝对象之间发生改变。

  7. 移动语义(Move Semantics):
    移动语义是一种优化技术,用于在对象转移时避免不必要的内存复制。通过使用移动构造函数和移动赋值运算符,对象的资源(如动态分配的内存)可以在转移后被接收方使用,而不需要进行复制。这在提高程序性能和减少资源占用方面是有益的。

2.应用实例

v1.0 浅拷贝

#include <iostream>class MyClass {
public:int value;MyClass(int val = 0) : value(val) {}void printValue() const {std::cout << "Value: " << value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2 = obj1; // 浅拷贝obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

v2.0 深拷贝

#include <iostream>
#include <cstring> // for memcpyclass MyClass {
public:int* value;MyClass(int val = 0) {value = new int(val);}~MyClass() {delete value;}MyClass(const MyClass& other) {value = new int;memcpy(value, other.value, sizeof(int));}void printValue() const {std::cout << "Value: " << *value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2 = obj1; // 深拷贝obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

v3.0 拷贝构造函数

#include <iostream>class MyClass {
public:int value;MyClass(int val = 0) : value(val) {}MyClass(const MyClass& other) : value(other.value) {}void printValue() const {std::cout << "Value: " << value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2(obj1); // 使用拷贝构造函数obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

4.0 拷贝赋值运算符

#include <iostream>class MyClass {
public:int value;MyClass(int val = 0) : value(val) {}MyClass& operator=(const MyClass& other) {if (this != &other) {value = other.value;}return *this;}void printValue() const {std::cout << "Value: " << value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2;obj2 = obj1; // 使用拷贝赋值运算符obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

v5.0 自定义的深拷贝函数

#include <iostream>class MyClass {
public:int* value;MyClass(int val = 0) {value = new int(val);}~MyClass() {delete value;}void deepCopyFrom(const MyClass& other) {*value = *other.value;}void printValue() const {std::cout << "Value: " << *value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2;obj2.deepCopyFrom(obj1); // 使用自定义的深拷贝函数obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

v6.0 通过指针进行拷贝

#include <iostream>class MyClass {
public:int* value;MyClass(int val = 0) {value = new int(val);}MyClass(const MyClass& other) {value = new int(*other.value);}~MyClass() {delete value;}void printValue() const {std::cout << "Value: " << *value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2 = obj1; // 通过指针进行拷贝obj1.printValue(); // 输出: Value: 10obj2.printValue(); // 输出: Value: 10return 0;
}

v7.0 移动语义

#include <iostream>class MyClass {
public:int* value;MyClass(int val = 0) {value = new int(val);}MyClass(MyClass&& other) : value(other.value) {other.value = nullptr;}~MyClass() {delete value;}void printValue() const {std::cout << "Value: " << *value << std::endl;}
};int main() {MyClass obj1(10);MyClass obj2 = std::move(obj1); // 移动语义obj1.printValue(); // 这里会输出一个未定义的值(因为已移动)obj2.printValue(); // 输出: Value: 10return 0;
}

v8.0 将对象other的内容复制到当前对象中(即this指针)

```cpp
#include <iostream>
#include <cstring>class MyClass {
public:int value;void copyFrom(const MyClass& other) {memcpy(this, &other, sizeof(MyClass));}
};int main() {MyClass obj1;obj1.value = 10;MyClass obj2;obj2.copyFrom(obj1);std::cout << "obj2.value: " << obj2.value << std::endl;return 0;
}

1.优点:
使用memcpy函数将&other对象的内存内容复制到this指针所指向的内存中。这样做的目的是实现对象之间的值复制,包括成员变量的值以及可能存在的虚函数表指针等。

2.缺点:
虽然使用memcpy可以将对象的内存内容直接复制到目标对象,但这种方式可能会导致未定义行为。这是因为memcpy是对内存进行字节级别的复制,无法处理对象中的特殊情况,如动态分配的内存、虚函数表指针等。因此,对于自定义的类,更推荐使用逐个复制成员变量的方式来实现对象之间的值复制,以确保复制的正确性和安全性。例如:

void copyFrom(const MyClass& other) {this->value = other.value;// 在实际的代码中,可能还需要逐个复制其他成员变量
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138118.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四、数学建模之图与网络模型

1.定义 2.例题及软件代码求解 一、定义 1.图和网络是相关概念 &#xff08;1&#xff09;图&#xff08;Graph&#xff09;&#xff1a;图是数学和计算机科学中的一个抽象概念&#xff0c;它由一组节点&#xff08;顶点&#xff09;和连接这些节点的边组成。图可以是有向的&…

vector使用和模拟实现

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; C&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大…

wx.getPrivacySetting 小程序隐私保护指引的使用(复制粘贴即用)

创建privacyPopup 组件 privacyPopup.js Component({properties: {},data: {wxPrivacyName: ,showAgreement: false},lifetimes: {attached() {this.init();}},methods: {async init() {if (isLogin()) {const userPrivacy await this.getPrivacy();this.setData({wxPrivacy…

C语言文件的相关操作

C语言中文件的相关操作 文件的打开 使用文件的打开函数需要引入这个头文件&#xff1a;#include <fcntl.h> open函数 int open(char const *pathname, int flags, mode_t mode) 功能&#xff1a;打开已有的文件或者创建新文件参数 pathname&#xff1a;文件路径名&…

Vue 使用vue-cli构建SPA项目(超详细)

目录 一、什么是vue-cli 二&#xff0c;构建SPA项目 三、 运行SPA项目 前言&#xff1a; 在我们搭建SPA项目时候&#xff0c;我们必须去检查我们是否搭建好NodeJS环境 cmd窗口输入以下指令&#xff1a;去检查 node -v npm -v 一、什么是vue-cli Vue CLI&#xff08;Vu…

控制台日志打印console的封装,加入美化、行显示与打印开关,支持node.js环境

控制台日志打印console的封装&#xff0c;加入美化、行显示与打印开关&#xff0c;支持node.js环境 为什么要写这个&#xff1f; 封装这个控制台日志打印工具&#xff0c;主要是在项目中自己做的SDK需要提供给其他开发人员使用&#xff0c;加入了日志美化和打印打开&#xff…

jq命令安装与使用

目录 一、简介二、下载及安装1.Linux 安装2.Windows 安装3.测试安装结果 三、jq用法1.基本语法2.常见用法1&#xff09;格式化 JSON2&#xff09;获取属性3&#xff09;属性不存在情况处理4&#xff09;数组遍历、截取、展开5&#xff09;管道、逗号、加号6&#xff09;数据构造…

Linux 系统目录结构 终端

系统目录结构 Linux 或 Unix 操作系统中&#xff0c;所有文件和目录呈一个以根节点为始的倒置的树状结构。文件系统的最顶层是根目录&#xff0c;用 / 来表示根目录。在根目录之下的既可以是目录&#xff0c;也可以是文件&#xff0c;而每一个目录中又可以包含子目录文件。如此…

宝塔重装注意事项

欢迎关注我的公众号&#xff1a;夜说猫&#xff0c;让一个贫穷的程序员不靠打代码也能吃饭~ 前言 宝塔8.0版本&#xff0c;宝塔卸载重装&#xff0c;或者重装Linux系统后重新安装宝塔也适用。 不能上来直接就执行安装宝塔脚本&#xff0c;除非之前没有安装过宝塔。 步骤 1、…

2023年浙工商MBA新生奖学金名单公布,如何看待?

浙工商MBA项目官方最新公布了2023年的非全日制新生奖学金名单&#xff0c;按照政策约定&#xff0c;共分为特等奖学金1名&#xff0c;一等奖学金10名&#xff0c;二等奖学金15名&#xff0c;三等奖学金30名&#xff0c;额度对应3万、1万、0.8万、0.5万不等&#xff0c;主要名单…

MySQL主从数据库搭建

1 背景 最近工作需要对比几种数据库技术方案&#xff0c;主从读写分离集群也是其中之一。现将该集群搭建过程记录下来&#xff0c;以便后面查看回忆。 2 主从集群 2.1 原理 主从复制的原理如下图所示&#xff1a; 2.2 集群划分 我在搭建主从集群时已经使用用虚拟机安装了do…

面试官:你是怎么理解ES6中 Decorator 的?使用场景?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、介绍 二、用法 类的装饰 类属性的装饰 注意 三、使用场景 antobind readonly deprecate 一、介绍 Dec…

BSV 上用于通用计算的隐私非交互式赏金

如何安全地外包任何计算 我们提出了一种新颖的赏金机制&#xff0c;可以在区块链上安全私密地外包任意计算。解决方案和付款的交换是原子的和无需信任的&#xff1a;赏金发布者获得解决方案而赏金收集者获得奖励&#xff0c;或者两者都不发生。赏金发布者部署一个智能合约&…

Layui + Flask | 实现注册、登录功能(案例篇)(08)

此案例内容比较多,建议滑到最后点击阅读原文,阅读体验更佳。后续也会录制案例视频,将在本周内上传到同名的 b 站账号。 已经看了 layui 表单相关的知识,接下来就可以实现注册功能,功能逻辑如下: 项目创建 新建 flask 项目下载 layui 文件,解压之后复制到指定文件编写前…

PostgreSQL设置主键为自增

1、创建自增序列 CREATE SEQUENCE table_name_id_seq START 1; 2、设置字段默认值 字段默认值中设置 nextval(table_name_id_seq) 3、常用查询 -- 查询所有序列 select * from information_schema.sequences where sequence_schema public; -- 查询自增序列的当前值 select cu…

Unity中UI组件对Shader调色

文章目录 前言一、原理在Shader中直接暴露的Color属性&#xff0c;不会与UI的Image组件中的Color形成属性绑定。因为UI的Image组件中更改的颜色是顶点颜色&#xff0c;如果需要在修改组件中的颜色时&#xff0c;使Shader中的颜色也同时改变。那么就需要在应用程序阶段传入到顶点…

自动驾驶中的决策规划

参考: 【干货篇】轻舟智航&#xff1a;自动驾驶中的决策规划技术&#xff08;附视频回放 PPT 下载&#xff09; - AIQ 如图所示, 各模块介绍 定位模块主要负责解答的问题是“车现在在哪里”&#xff0c;是在道路上还是在路口&#xff0c;是在高架桥上还是在停车场里。 感知…

Redis 集合(Set)快速指南 | Navicat

Redis 支持通过多种数据类型来存储项目集合。其中&#xff0c;包括列表、集合和哈希。上周的博文介绍了列表&#xff08;List&#xff09;数据类型并重点介绍了一些用于管理列表&#xff08;List&#xff09;的主要命令。在今天的文章中&#xff0c;我们将转向关注集合&#xf…

怒刷LeetCode的第11天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;迭代 方法二&#xff1a;递归 方法三&#xff1a;指针转向 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;快慢指针 方法二&#xff1a;Arrays类的sort方法 方法三&#xff1a;计数器 方法四…

Neo4j图数据库_web页面关闭登录实现免登陆访问_常用的cypher语句_删除_查询_创建关系图谱---Neo4j图数据库工作笔记0013

由于除了安装,那么真实使用的时候,就是导入数据了,有了关系和节点的csv文件以后如果用 cypher进行导入数据和创建关系图谱,还有进行查询,以及如果导入错误如何清空,大概是这些 用的最多的,单独把这些拿进来,总结一下,用的会比较方便. 1.实现免登陆访问: /data/module/neo4j-…