当前位置: 首页 > news >正文

【C++ 】string类:深拷贝与浅拷贝解析

【C++ 】string类操作全解析-CSDN博客

1.stirng类的模拟实现

1.1 经典的string类问题

上面已经对string类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢要求自己来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数。大家看下以下string类的实现是否有问题?

// 为了和标准库区分,此处使用String 
class String 
{ 
public:/*String()  :_str(new char[1])  {*_str = '\0';}  */  //String(const char* str = "\0") 错误示范  //String(const char* str = nullptr) 错误示范 String(const char* str = "") {  // 构造String类对象时,如果传递nullptr指针,可以认为程序非  if (nullptr == str) { assert(false);  return; }  _str = new char[strlen(str) + 1];  strcpy(_str, str); }  ~String() {  if (_str) {  delete[] _str;  _str = nullptr; } } private:  char* _str; 
}; // 测试 
void TestString() 
{  String s1("hello!!!");  String s2(s1); 
}

说明:上述String类没有显式定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造。最终导致的问题是,s1、s2共用同一块内存空间,在释放时同一块空间被释放多次而引起程序崩溃,这种拷贝方式,称为浅拷贝。

String(const char* str = "") 中,str 的类型必须是 const char*,不能去掉 const

代码中默认参数 "" 是 字符串字面量(比如 "hello""" 这类用双引号包裹的内容),在 C++ 中: 字符串字面量存储在程序的「只读数据段」(不能被修改),其类型本质是 const char[](常量字符数组)。

当把字符串字面量赋值给指针时,编译器会自动将其转换为 const char*(指向常量的指针)—— 这是为了防止通过指针修改只读内存中的内容(否则会触发「未定义行为」,比如程序崩溃)。

1.2 浅拷贝

浅拷贝的核心问题(多对象共享资源 + 重复释放)

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规

就像一个家庭中有两个孩子,但父母只买了一份玩具,两个孩子愿意一块玩,则万事大吉,万一不想分享就你争我夺,玩具损坏。

可以采用深拷贝解决浅拷贝问题,即:每个对象都有一份独立的资源,不要和其他对象共享。父母给每个孩子都买一份玩具,各自玩各自的就不会有问题了

重点:

当我们用一个 String 对象拷贝构造另一个对象时,如果没有自己实现拷贝构造函数,编译器会自动生成「浅拷贝构造函数」。

浅拷贝的本质是「位拷贝」—— 把原对象的所有成员变量的值,逐字节拷贝到新对象,包括指向资源的指针(_str)。

图解:

String s1("hello");  // 1. 创建s1,申请内存存"hello"
String s2 = s1;       // 2. 浅拷贝:用s1构造s2(编译器自动生成)

拷贝前(s1 单独存在):

s1:_str: 0x100(动态内存地址)_size: 5_capacity: 5↓0x100内存:['h','e','l','l','o','\0']  // s1管理的资源

浅拷贝后(s2 与 s1 的状态):

s1:                  s2:_str: 0x100         _str: 0x100  // 指针值相同!指向同一块内存_size: 5            _size: 5     // 数值拷贝_capacity: 5        _capacity: 5 // 数值拷贝↓0x100内存:['h','e','l','l','o','\0']  // 两个对象共享同一份资源

浅拷贝没有为新对象(s2)重新申请新的动态内存,只是让 s2 的 _str 指针,指向了和 s1 的 _str 相同的内存地址 —— 即 s1 和 s2 共享同一份动态内存资源。

[创建s1] → s1._str指向0x100(内存有效)↓
[浅拷贝s2] → s2._str也指向0x100(共享资源)↓
[程序结束,s2先析构] → delete 0x100(内存变为无效)↓
[ s1再析构 ] → 试图delete 0x100(无效内存)→ 访问违规!

1.3 深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

strcpy 的工作原理是:从源字符串逐个拷贝字符(包括终止符 '\0'),直到遇到源字符串的 '\0' 才停止。

// 深拷贝构造函数(自己实现)
String(const String& s) {_size = s._size;_capacity = s._capacity;_str = new char[_capacity + 1];  // 1. 为新对象申请新内存strcpy(_str, s._str);            // 2. 把原资源的数据拷贝过来
}
s1:                  s2:_str: 0x100         _str: 0x200  // 指针指向不同内存_size: 5            _size: 5_capacity: 5        _capacity: 5↓                    ↓
0x100: "hello"    0x200: "hello"  // 各自拥有独立资源

http://www.dtcms.com/a/359951.html

相关文章:

  • DSPFilters实现低通滤波器(QT)
  • 电力电子技术知识学习-----晶闸管
  • 前端组件拆分与管理实战:如何避免 props 地狱,写出高可维护的项目
  • 接口测试:如何定位BUG的产生原因
  • Python实现异步多线程Web服务器:从原理到实践
  • 萌宝喂养日志-我用AI做喂养记录小程序1-原型设计
  • 微服务的编程测评系统18-判题功能-Rabbitmq-用户拉黑
  • Elasticsearch面试精讲 Day 3:分片与副本策略详解
  • 【图论】 Graph.jl 概览
  • Linex进程管理
  • OC-属性关键字
  • GEE 实战:计算 Landsat8 月均 NDVI 并导出(2013-2024)_后附完整代码
  • 【pve】
  • 秋招 AI 方向 —— 华为机考
  • 【学习笔记】LLM Interview(Agent相关)
  • 计算机视觉与深度学习 | 低照度图像处理算法综述:发展、技术与趋势
  • 大数据毕业设计选题推荐-基于大数据的大气和海洋动力学数据分析与可视化系统-Spark-Hadoop-Bigdata
  • (数组的定义与使用) 本篇目标 1. 理解数组基本概念 2. 掌握数组的基本用法 3. 数组与方法互操作 4. 熟练掌握数组相关的常见问题和代码
  • 同类软件对比(三):Python vs Anaconda vs Miniconda:深入解析与选择策略
  • 2025.8.18-2025.8.24第35周:备稿演讲有进步
  • Paimon——官网阅读:Spark 引擎
  • 【图论】Graph.jl 核心函数
  • 如何通过 AI IDE 集成开发工具快速生成简易留言板系统
  • Java面试-微服务(spring cloud篇)
  • 飞牛Docker部署免费frp内网穿透
  • RK3568平台开发系列讲解:瑞芯微平台4G模块篇移植
  • TFS-2005《A Possibilistic Fuzzy c-Means Clustering Algorithm》
  • 商业航天:中、美、欧“软件定义卫星” 路线全解析
  • Iterative loop of ML development|机器学习的迭代发展
  • JavaEE初阶网络原理-初识