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

【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.xdnf.cn/news/19382.html

相关文章:

  • ​​告别通用模型局限:5步微调实战指南​
  • 数值分析——非线性方程与方程组的数值解法之迭代法
  • [灵动微电子 MM32BIN560CN MM32SPIN0280]读懂电机MCU 模拟输入运放放大
  • NCCL-TEST ib集群测试UCX代替方案
  • unity tilemap grid 的中心轴
  • Linux中卸载和安装Nginx
  • Python爬虫实战:研究Figures与 Axes,构建社交平台具有决策价值的数据采集和分析系统
  • C 语言进程通信之信号API
  • python---封装
  • MySQL 8 的 SQL 语法新特性
  • 《哲思:生命与宇宙的终极意义》
  • 【Canvas技法】绘制横向多色旗和竖向多色旗
  • Python入门教程:常用第三方库Matplotlib(基本用法)下载、安装、参数解析教程
  • ibping基本使用 以及 包丢失 超时 排障
  • 设计模式 | 常见的设计模式(单例、工厂、代理、适配器、责任链等等)
  • 2025年9月计算机二级C++语言程序设计——选择题打卡Day12
  • Langflow 多模态技术深度分析
  • Hysplit大气传输和污染扩散-轨迹聚合标准20%30%用途
  • OpenCV 图像直方图与对比度增强实战:从分析到优化
  • Week 14: 深度学习补遗:迁移学习
  • 《隐性质量:决定软件生命周期的看不见的竞争力》
  • Langflow Agents 技术深度分析
  • 极客学院-从零开始学架构
  • MCP SDK 示例一
  • Linux 特殊文件系统
  • 二、程序设计语言基础知识
  • 预售破 500 万!淮北吾悦广场京东奥莱8月29日开业燃动皖北
  • Pytest+Selenium4 Web自动化测试框架(三日速通)
  • ANR InputDispatching TimeOut超时判断 - android-15.0.0_r23
  • python如何打开显示svg图片