深拷贝vs浅拷贝,引用传递vs值传递vs指针传递

探索 JavaScript 中的“影子世界”:引用(Reference)的奥秘 你是否曾在 JavaScript 中修改了一个变量,却发现另一个变量也“神秘”地发生了变化?或者明明两个数组看起来一模一样,却无法通过 === 比较?这一切的背后,都是 引用(Reference) 在“搞鬼”! 在这篇博客中,我们将揭开 JavaScript 中引用的神秘面纱,带你深入理解它的工作原理,并教你如何避免常见的“引用陷阱”。无论你是初学者还是经验丰富的开发者,这篇文章都会为你提供实用的技巧,让你的代码更加健壮和高效。准备好了吗?让我们一起进入 JavaScript 的“影子世界”吧! 阅读详情

一、值传递

函数调用时传递对象,会调用拷贝构造函数(可能是浅拷贝或深拷贝,取决于类如何定义)

二、引用传递

函数调用时传递对象的引用,不调用拷贝构造函数,直接对原值进行操作

三、指针传递

将原指针复制一份传递给函数,本质也属于值传递,在函数内部可以修改副本指针指向的地址(不影响原指针的指向),或者可以用*解引用来直接修改原地址的值。

四、三种传递方法的示例和总结

#include <stdio.h>

//此函数需要在C++中运行,C语言中没有引用传递,在C语言中此函数会报错,在C语言可以用指针传递代替引用传递
int setValue(int& a,int b){  // 变量a是引用传递,直接对原始变量进行操作,变量b是值传递,会拷贝原变量b生成副本
    a=3;  // 修改的是原变量
    b=6;  // 修改的是局部副本
    return a+b;  // 返回 3+6=9
}


int setValue2(int* a,int b){  // 变量a是指针传递,会拷贝原变量的地址,变量b是值传递,会拷贝原变量f生成副本
    printf("局部变量a的值:%p\n",a);//可以发现a的值就是原变量的地址
    *a=3;  // 通过解引用修改地址中的值,等同于修改的是原变量
    b=6;  // 修改的是局部副本
    return *a+b;  // 返回 3+6=9
}


int main(){
    //对比引用传递和值传递
    int a=5;
    int b=5;
    int c = setValue(a,b);
    printf("a:%d, b:%d, c:%d\n",a,b,c);//可以发现a被修改了,但是b未被修改

    //对比指针传递和值传递
    int e=5;
    int f=5;
    int g = setValue2(&e,f);
    printf("原变量e的地址:%p\n",&e);
    printf("e:%d, f:%d, g:%d\n",e,f,g);//可以发现e被修改了,但是f未被修改
} 

特性值传递指针传递引用传递
语言支持C/C++C/C++C++特有
传递内容变量的副本变量的地址变量的别名
修改原值不可能可以(需解引用)可以直接修改
内存开销复制整个数据固定大小(指针大小)通常无额外开销
空值安全总是安全需要检查空指针必须绑定有效对象

五、浅拷贝

默认的拷贝构造函数(只复制指针,不复制指针指向的数据)

六、深拷贝

自定义拷贝构造函数(复制指针指向的数据)

七、两种拷贝方式示例

#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
    
    int age;
    
public:
    char* name;  // 动态分配的姓名
    // 构造函数
    Person(const char* name, int age) : age(age) {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        std::cout << "构造函数: " << name << std::endl;
    }
    
    // 浅拷贝构造函数(危险!)
    Person(const Person& other) : name(other.name), age(other.age) {
        std::cout << "浅拷贝构造函数: " << name << std::endl;
    }
    
    // 析构函数
    ~Person() {
        std::cout << "析构函数: " << name << std::endl;
        delete[] name;
    }
    
    void print() const {
        std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
    }
    
    void setName(const char* newName) {
        strcpy(name, newName);
    }
};

class Person2 {
private:
    
    int age;
    
public:
    char* name;  // 动态分配的姓名
    // 构造函数
    Person2(const char* name, int age) : age(age) {
        this->name = new char[strlen(name) + 1];
        strcpy(this->name, name);
        std::cout << "构造函数: " << name << std::endl;
    }
    
    //深拷贝构造函数(安全)
    Person2(const Person2& other) : age(other.age) {
        name = new char[strlen(other.name) + 1];
        strcpy(name, other.name);
        std::cout << "深拷贝构造函数: " << name << std::endl;
    }
    
    // 析构函数
    ~Person2() {
        std::cout << "析构函数: " << name << std::endl;
        delete[] name;
    }
    
    void print() const {
        std::cout << "姓名: " << name << ", 年龄: " << age << std::endl;
    }
    
    void setName(const char* newName) {
        strcpy(name, newName);
    }
};
 
// 值传递函数
void passByValue1(Person p) {
    std::cout << "值传递内部: ";
    p.print();
    p.setName("内部修改");
}

// 值传递函数
void passByValue2(Person2 p) {
    std::cout << "值传递内部: ";
    p.print();
    p.setName("内部修改");
}
 
// 引用传递函数  
void passByReference1(Person& p) {
    std::cout << "引用传递内部: ";
    p.print();
    p.setName("内部修改");
}

// 引用传递函数  
void passByReference2(Person2& p) {
    std::cout << "引用传递内部: ";
    p.print();
    p.setName("内部修改");
}
 
int main() {
    std::cout << "\n=== 引用传递 (高效安全) ===" << std::endl;
    {
        Person charlie("Charlie", 35);
        passByReference1(charlie);  // 引用传递,不拷贝
        std::cout << "引用传递后原始对象: ";
        charlie.print();  // 原始对象被修改
    }  // 正常析构

    std::cout << "\n=== 深拷贝 + 值传递 (安全示例) ===" << std::endl;
    {
        // 使用深拷贝构造函数的情况
        Person2 bob("Bob", 30);
        passByValue2(bob);  // 值传递触发深拷贝
        std::cout << "bob.name指针值: " << static_cast<void*>(bob.name) << std::endl;
        std::cout << "值传递后原始对象: ";
        bob.print();  // 原始对象不受影响
    }  // 正常析构,没有内存问题

    std::cout << "=== 浅拷贝 + 值传递 (危险示例) ===" << std::endl;
    {
        Person alice("Alice", 25);
        passByValue1(alice);  // 值传递触发浅拷贝
        std::cout << "引用传递后原始对象: ";
        alice.print();  // 原始对象被修改
        //这里会导致双重释放错误!因为在passByValue中采用浅拷贝构造了对象p,p的name指针和alice的name指针指向同一块内存,而在passByValue函数运行结束p对象被释放,此刻alice的name指针就变成了悬空指针
        //而在出代码块alice会调用析构导致alice.name双重释放,此时可能出现乱码,原因:析构函数尝试读取已释放内存的内容,读到的是一些随机数据(内存垃圾)
    }
    
    return 0;
}

安时积分法和开路电压法结合估算锂电池SOC 基于安时积分法和开路电压法结合的锂电池SOC估计Simulink仿真建模,利用安时积分法计算放电过程中的SOC,在搁置状态利用开路电压法进行SOC修正。 阅读详情

相关推荐

风二西CTF流量题大集合-刷题笔记|基础题(1)

部分题目已包含脚本和解题视频,但更建议自行分析和手搓脚本。

zerorzeror的博客 2765

c++的深拷贝和浅拷贝

c++中深拷贝和浅拷贝的出现时因为他多了指针和引用的概念   本质就是对别的资源的引用  即指向改资源的内存地址 在一般没有指针或者引用的对象的拷贝的时候浅拷贝就够了,如果多了指针或者引用的属性的时候就涉及到深拷贝了 ,手动设定拷贝函数,开辟一样大小的内存空间,  CCopyTest(const CCopyTest& _copy):size(_copy.size){data=new in

shantsc的专栏 464

如何缩减layout电路面积?减少晶体管的数量——以全加器为例【VLSI】

How to reduce the number of transistors to reduce circuit area? -- Take the Binary Full Adder as an example 优化面积的方法 1. 减少晶体管的数量 2. 改变gate matrix的布局

Jie_MSD的博客 6433

深拷贝和浅拷贝的区别

目录 深拷贝和浅拷贝 值类型 vs 引用类型 赋值 vs 浅拷贝 vs 深拷贝 对象赋值 浅拷贝 深拷贝 浅拷贝代码实现 深拷贝代码实现 深度遍历式拷贝 利用反序列化实现深拷贝 深拷贝和浅拷贝 浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址, 深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存, 使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。 浅复制:仅仅是指向被复制的.

一蓑烟雨任平生 4753

AI落地困局与破局者FDE:从技术神话到价值实干的战略转型

AI落地困局与破局者FDE:从技术神话到价值实干的战略转型 当前AI企业级应用面临三大核心挑战:业务场景深度非标化、技术落地"最后一公里"困局、以及市场竞争焦点转向实用价值。前线部署工程师(FDE)作为破局关键,通过技术-业务-产品三维交汇的复合能力,将AI从实验室推向生产环境。FDE不仅是技术架构师,更是业务价值挖掘机和产品进化传感器,通过"碎石路-高速公路"双循环模式,将定制化需求沉淀为可复用的平台能力。这种模式颠覆了传统SaaS的销售逻辑,形成基于价值的J型增长

随笔记录-分享&记忆 4003

从勒索软件攻击到数据重生:SQL Server MDF文件修复的实战生存指南

本文详细介绍了SQL Server MDF文件在遭遇勒索软件攻击后的修复策略,重点解析了Recovery Toolbox工具链的应用流程。从灾难评估到数据验证,提供分阶段修复操作、高级修复技术及防御加固方案,帮助企业快速恢复数据库并提升安全防护能力。

weixin_28327051的博客 715

python传递指针_按值传递 vs. 按指针传递

按值传递还是指针传递?变量赋值有两种方式:按值传递、按"指针"传递(指针也常称为"引用")。不同的编程语言赋值的方式不一样,例如python是按"指针"传递的,go是按值传递的。注意,"指针"加了引号,因为它不是真正的按指针拷贝,见下文分析。参数传值其实也是变量赋值的过程,只不过参数是函数的本地变量而已。按值传递的意思是每次赋值都拷贝内存中完整的数据结构对象,这时在内存中会保存两份内容完全相同,但...

weixin_36212732的博客 1404

2025国赛数学建模A题 完整Python代码 烟幕干扰弹的投放策略

常量定义G = 9.8 # 重力加速度 m/s²V_SMOKE_SINK = 3 # 烟幕下沉速度 m/sMISSILE_SPEED = 300 # 导弹速度 m/sEFFECTIVE_RADIUS = 10 # 有效遮蔽半径 mEFFECTIVE_DURATION = 20 # 有效遮蔽时间 sTARGET_POS = np.array([0, 200, 0]) # 目标位置FALSE_TARGET_POS = np.array([0, 0, 0]) # 假目标位置# 初始位置。

YOLO 1106

python 指针_按值传递 vs. 按指针传递

按值传递还是指针传递?变量赋值有两种方式:按值传递、按"指针"传递(指针也常称为"引用")。不同的编程语言赋值方式不一样,Python是按"指针"传递的,Go是按值传递的。拉勾IT课小编为大家分解注意,"指针"加了引号,因为它不是真正的按指针拷贝,见下文分析。参数传值其实也是变量赋值的过程,只不过参数是函数的本地变量而已。按值传递的意思是每次赋值都拷贝内存中完整的数据结构对象,这时在内存中会保存两...

weixin_39613291的博客 460

【GameFramework框架内置模块】9、有限状态机(FSM)

这篇文章分享FSM有限状态机,了解过StarForce源码的同学相比都比较了解,GameFramework框架给我们抽象了一个Procedure流程的概念。这个Procedure流程可以方便的处理我们游戏从启动到游戏的各个流程阶段的处理逻辑,实现的核心就是FSM状态机,内部的Procedure流程就是不同的FsmState状态。接下来,就是FSM有限状态机的教程了。有限状态机(Finite-state machine,FSM)

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2533

改进后的yolov8导出进行部署到rk3588上时,导出为onnx格式报错aten::fft_fft2算子不支持导出...如何解决?

🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 备注:部分问题/疑难杂症搜集于互联网。

**My Coding Family** 1798

python按值划分_按值传递 vs. 按指针传递

按值传递还是指针传递?变量赋值有两种方式:按值传递、按"指针"传递(指针也常称为"引用")。不同的编程语言赋值方式不一样,Python是按"指针"传递的,Go是按值传递的。拉勾IT课小编为大家分解注意,"指针"加了引号,因为它不是真正的按指针拷贝,见下文分析。参数传值其实也是变量赋值的过程,只不过参数是函数的本地变量而已。按值传递的意思是每次赋值都拷贝内存中完整的数据结构对象,这时在内存中会保存两...

weixin_39563420的博客 85

高通平台蓝牙学习-- 基于WCN6750 Bluetooth 5.2的讲解

摘要:蓝牙5.2解决方案WCN6750具备多项先进特性:完全兼容5.2标准及ANT+协议,支持2Mbps高速BLE和长距离传输;采用射频集成方案,与WLAN共享天线并支持5G并发;内置功率放大器,支持Class1/2传输;提供双音频流和Slimbus接口优化。其HCI UART接口支持3.2Mbps速率,通过BlueZ协议栈实现蓝牙5.2功能,包括2Mbps模式和长距离传输,符合核心规范要求。(149字)

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 3万+

python深拷贝和浅拷贝

并不会创建新的对象,而是创建一个新的引用指向原对象。因此,修改新的引用会影响原对象。(指针),而非数据本身。因此,Python 的参数传递是。是 Python 编程中非常重要的概念。Python 变量的赋值、参数传递,以及。(可变对象会被修改,不可变对象不会修改)来讲解,并给出示例帮助你理解。,保证新对象和原对象完全独立。在 Python 中,赋值。(但有时表现得像值传递)。Python 变量分为。,所有变量实际上存的是。,不复制内部嵌套对象。

大多_C的博客 907

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C++知识点之深拷贝和浅拷贝

1、引言。 今天复习到C++深拷贝和浅拷贝的知识点。现在,做个梳理。 2、浅拷贝。(反例) 2.1 实例。 #include <iostream> using namespace std; class Person { public: Person(int nHeight, int nWeight); ~Person(); //我们自己来写系统生成的Default Copy ...

Struggling_Jeff的博客 454

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

c++中的拷贝构造函数,浅拷贝,深拷贝

c++拷贝构造函数,深拷贝和浅拷贝

cyz322649的博客 1620

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)

参考了:点击打开链接以及《高质量程序设计指南C++/C语言》 说明 拷贝构造函数是一种特殊的构造函数。相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。 函数的名称必须和类名称一致。 它的参数是唯一的,该参数是const类型的引用变量。例如 类X的拷贝构造函数的形式为X(X& x)。 Q:为啥拷贝构造函数的参数必须是同类对象的引用,而不能是值传递? 请看下面的例子: cl

ywok526的专栏 2586

10.深拷贝和浅拷贝的区别?

本文摘要: C++内存管理技术对比分析:1) 浅拷贝仅复制指针,易导致double free;深拷贝复制内存内容,资源类必须实现深拷贝或禁用拷贝。2) 零拷贝技术(如sendfile、mmap)通过避免用户态-内核态数据拷贝提升IO性能。3) 关键函数区别:strlen计算字符串长度,sizeof计算内存大小;memcpy支持任意数据拷贝,strcpy仅限字符串。4) 对象处理机制:重载是同名函数不同参数,重写是子类覆盖虚函数;临时对象产生于返回值、类型转换等场景,C++17优化可消除。5) static变

2302_77573185的博客 1022

Go函数参数传递:值传递与指针传递、slice和map修改效果详解

在编程语言中,函数参数传递方式决定了数据在函数内外的同步行为,而Go语言遵循的“值传递”规则却隐藏着不少反直觉的细节:基本类型复制的是纯数据,指针传递复制的是地址,slice复制的是头部结构但共享底层数组,map复制的是引用头但底层哈希表共享。理解这些差异,是掌握Go编程的关键基础。通过解析值传递与指针传递的原理,区分值类型与引用类型,并深入探讨slice扩容、map修改、结构体传值等高频场景,开发者能够准确预判函数修改是否会影响外部变量,从而设计出更清晰、更安全的函数签名。本文从基础概念出发,结合实际工程

weixin_33874713的博客 448

【java基础】浅拷贝/深拷贝

本篇实验内容转载于:https://www.bilibili.com/read/cv7349900 作者:CodeSheep   本来是日常编写C语言代码的刚性需求,虽然java经常忽悠人说自己是不存在指针的,但实际上java底层的JVM是用C和C++写的(就比如操作数栈、堆之类的实现都可以说是存在指针的),一句话形容就是:java的嘴,骗人的鬼。 值类型 vs 引用类型   在java的世界里,像数组、类Class、枚举Enum、Integer包装类等等,就是典型的引用类型,所以操作时一般来说采用.

qq_43654226的博客 175

按值传递 vs. 按指针传递

按值传递还是指针传递? 变量赋值有两种方式:按值传递、按"指针"传递(指针也常称为"引用")。不同的编程语言赋值的方式不一样,例如Python是按"指针"传递的,Go是按值传递的。 注意,"指针"加了引号,因为它不是真正的按指针拷贝,见下文分析。 参数传值其实也是变量赋值的过程,只不过参数是函数的本地变量而已。 按值传递的意思是每次赋值都拷贝内存中完整的数据结构对象,这时在内存中会保存两份内容完全...

weixin_34327223的博客 188

深拷贝vs浅拷贝

1. 浅拷贝:对基本的数据类型进行值传递,对引用数据类型只是增加了一个指向同一个堆里对象的指针,这是浅拷贝。 2. 深拷贝:对基本的数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,这是深拷贝。 ...

qq_38197844的博客 117

【C++核心编程】拷贝构造&赋值运算符&深拷贝浅拷贝

🔥❤️类名(const 类名& 对象名) { ... }为了避免浅拷贝带来的问题,我们通常会实现深拷贝(Deep Copy)。深拷贝会创建一个新的内存空间,并复制对象中所有指针指向的数据,而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值。这样就不会出现通过成员指针对指向数据进行修改,另外一个对象的指针成员的指向也被修改。还有一块内存被释放两次的错误。int* m_ptr;//没有重载的普通构造函数CTest() {m_age = 0;

代码兴国 1266

深入C++的拷贝构造和赋值函数 (深拷贝,浅拷贝)

说明 拷贝构造函数是一种特殊的构造函数。相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。 函数的名称必须和类名称一致。 它的参数是唯一的,该参数是const类型的引用变量。例如 类X的拷贝构造函数的形式为X(X& x)。 Q:为啥拷贝构造函数的参数必须是同类对象的引用,而不能是值传递? 请看下面的例子: [cpp] view plaincopyprint?

苦行僧 581

C++深拷贝与浅拷贝核心辨析

特性拷贝构造函数赋值运算符浅拷贝深拷贝目的创建新对象并用现有对象初始化将现有对象状态赋给另一个已存在对象复制指针值(地址)复制指针指向的实际数据对象状态目标对象是新创建的目标对象已存在多个对象共享资源每个对象拥有资源的独立副本资源管理需为指针成员分配新内存并复制数据需释放旧资源,分配新内存并复制数据易导致双重释放、数据意外修改避免双重释放,确保对象独立性默认行为编译器生成,逐成员复制(浅拷贝)编译器生成,逐成员复制(浅拷贝)编译器默认行为(对指针危险)需手动实现关键风险。

q_438141的博客 162

深挖C++:类和对象(中)

(先进后出)

xys_678的博客 245
上一篇: C++的四种强制类型转换(解释+代码说明)
下一篇: 编译时检查vs运行时检查
10710
博客等级 码龄6年 1168粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10710

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值