【解码现代 C++】:实现自己的智能 【String 类】

目录

1. 经典的String类问题

1.1 构造函数

小李的理解

1.2 析构函数

小李的理解

1.3 测试函数

小李的理解

1.4 需要记住的知识点

2. 浅拷贝

2.1 什么是浅拷贝

小李的理解

2.2 需要记住的知识点

3. 深拷贝

3.1 传统版写法的String类

3.1.1 拷贝构造函数

小李的理解

3.1.2 赋值运算符重载

小李的理解

3.1.3 需要记住的知识点

4. 现代版写法的String类

4.1 拷贝构造函数

小李的理解

4.2 赋值运算符重载

小李的理解

4.3 需要记住的知识点

5. 写时拷贝(了解)

5.1 写时拷贝

小李的理解

5.2 需要记住的知识点

​编辑

6. 总结

小李的理解


 

专栏:C++学习笔记 

接上一篇:【掌握C++ string 类】——【高效字符串操作】的【现代编程艺术】

在C++中,std::string是一个非常常用的类,它封装了对C风格字符串的处理。但是,在某些情况下,我们可能需要自己实现一个类似string的类来展示对C++核心概念的掌握。本文将深入剖析一个自定义的String类的实现,特别关注其构造、拷贝构造、赋值运算符重载以及析构函数的实现。

1. 经典的String类问题

以下是一个初步的String类实现:

#include <iostream>
#include <cstring>
#include <cassert>class String {
public:// 构造函数,默认参数为空字符串String(const char* str = "") {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 bit!!!");String s2(s1);  // 默认拷贝构造
}int main() {TestString();return 0;
}

1.1 构造函数

  • 功能:用于初始化对象。
  • 操作
    • 检查输入指针是否为nullptr
    • 分配足够的内存存储字符串。
    • 拷贝字符串内容到新分配的内存中。
小李的理解
  • 构造函数:就像你去商店买东西,店员先检查你要买的东西是否存在,然后给你打包好交给你。

1.2 析构函数

  • 功能:用于释放对象占用的资源。
  • 操作
    • 检查指针是否为空。
    • 释放内存。
    • 将指针置为nullptr以避免悬挂指针。
小李的理解
  • 析构函数:当你不需要某样东西时,店员会帮你处理掉它,并确保不会再使用它。

1.3 测试函数

  • 功能:验证构造函数和析构函数的工作情况。
  • 操作
    • 创建两个String对象。
    • 用默认的拷贝构造函数创建第二个对象。
小李的理解
  • 测试函数:就像试用新买的东西,确保它们都能正常工作。

1.4 需要记住的知识点

  • 默认的拷贝构造函数执行的是浅拷贝(shallow copy)。
  • 多个实例共享同一块内存,当其中一个实例被销毁时,其他实例会尝试访问已经释放的内存,导致程序崩溃。

2. 浅拷贝

浅拷贝是指编译器仅仅复制对象中的值(即指针地址),而不是指针所指向的内容。这意味着多个对象会共享同一份资源,如上例中的字符数组:

String s1("hello bit!!!");
String s2(s1); // 浅拷贝,s1和s2共享同一块内存

2.1 什么是浅拷贝

  • 定义:浅拷贝只复制指针地址,多个对象共享同一份资源。
  • 问题:当一个对象释放内存时,其他对象会访问无效内存,导致程序崩溃。
小李的理解
  • 浅拷贝:就像两个孩子共用一个玩具,只有一个玩具,两人要共享。一个孩子用坏了,另一个孩子也不能用了。

2.2 需要记住的知识点

  • 浅拷贝会导致多个对象共享同一块内存。
  • 释放其中一个对象时,其他对象会尝试访问已释放的内存,导致程序崩溃。

3. 深拷贝

深拷贝则会创建对象时复制资源的内容,使每个对象拥有一份独立的资源。这需要显式定义拷贝构造函数和赋值运算符。以下是一个实现深拷贝的String类:

3.1 传统版写法的String

#include <iostream>
#include <cstring>
#include <cassert>class String {
public:// 构造函数String(const char* str = "") {if (nullptr == str) {assert(false);  // 断言检查return;}_str = new char[strlen(str) + 1];  // 分配内存strcpy(_str, str);  // 拷贝字符串}// 拷贝构造函数String(const String& s) {_str = new char[strlen(s._str) + 1];  // 分配内存strcpy(_str, s._str);  // 拷贝字符串}// 赋值运算符重载String& operator=(const String& s) {if (this != &s) {  // 自我赋值检查char* pStr = new char[strlen(s._str) + 1];  // 分配新内存strcpy(pStr, s._str);  // 拷贝字符串delete[] _str;  // 释放旧内存_str = pStr;  // 更新指针}return *this;}// 析构函数~String() {if (_str) {delete[] _str;  // 释放内存_str = nullptr;  // 避免悬挂指针}}private:char* _str;
};// 测试函数
void TestString() {String s1("hello bit!!!");String s2(s1);  // 使用拷贝构造函数String s3 = s2;  // 使用赋值运算符重载
}int main() {TestString();return 0;
}

3.1.1 拷贝构造函数

  • 功能:创建新对象时分配新的内存,并拷贝字符串内容。
  • 操作
    • 分配足够的内存存储字符串。
    • 拷贝字符串内容到新分配的内存中。
小李的理解
  • 拷贝构造函数:就像父母给每个孩子都买一份玩具,各自玩各自的,不会有冲突。

3.1.2 赋值运算符重载

  • 功能:确保自我赋值时不会出错,并实现深拷贝。
  • 操作
    • 检查自我赋值(如s = s)。
    • 分配新内存,拷贝字符串,释放旧内存,并更新指针。
小李的理解
  • 赋值运算符重载:就像你决定换掉旧的玩具,先买个新的,再把旧的处理掉,确保整个过程不会出错。

3.1.3 需要记住的知识点

  • 拷贝构造函数和赋值运算符必须显式定义以实现深拷贝。
  • 深拷贝确保每个对象都有独立的资源,避免共享同一块内存。

4. 现代版写法的String

现代C++中,可以利用临时对象和swap函数简化赋值运算符的实现:

#include <iostream>
#include <cstring>
#include <cassert>
#include <algorithm>  // 包含swap函数class String {
public:// 构造函数String(const char* str = "") {if (nullptr == str) {assert(false);  // 断言检查return;}_str = new char[strlen(str) + 1];  // 分配内存strcpy(_str, str);  // 拷贝字符串}// 拷贝构造函数String(const String& s): _str(nullptr) {String strTmp(s._str);  // 创建临时对象swap(_str, strTmp._str);  // 交换内容}// 赋值运算符重载String& operator=(String s) {swap(_str, s._str);  // 交换内容return *this;}// 析构函数~String() {if (_str) {delete[] _str;  // 释放内存_str = nullptr;  // 避免悬挂指针}}private:char* _str;
};// 测试函数
void TestString() {String s1("hello bit!!!");String s2(s1);  // 使用拷贝构造函数String s3 = s2;  // 使用赋值运算符重载
}int main() {TestString();return 0;
}

4.1 拷贝构造函数

  • 功能:利用临时对象实现深拷贝。
  • 操作
    • 创建一个临时对象。
    • 交换临时对象和当前对象的内容。
小李的理解
  • 拷贝构造函数:就像把新玩具给孩子,然后把旧玩具处理掉,确保整个过程不会出错。

4.2 赋值运算符重载

  • 功能:利用临时对象和swap函数简化赋值运算符的实现。
  • 操作
    • 利用临时对象进行深拷贝。
    • 交换临时对象和当前对象的内容。
小李的理解
  • 赋值运算符重载:就像在家里换家具时,先把新家具搬进来,再把旧家具搬走,确保整个过程不会出错。

4.3 需要记住的知识点

  • 现代C++中,利用swap和临时对象简化赋值运算符的实现,可以确保异常安全。
  • 这种方法使得代码简洁且高效。

5. 写时拷贝(了解)

写时拷贝(Copy-On-Write, COW)是一种优化技术,在实现浅拷贝的基础上增加引用计数。每次拷贝时增加引用计数,只有在实际写操作发生时才进行深拷贝:

#include <iostream>
#include <cstring>
#include <cassert>class String {
public:// 构造函数String(const char* str = "") {_str = new char[strlen(str) + 1];strcpy(_str, str);_refCount = new int(1);  // 引用计数}// 拷贝构造函数String(const String& s): _str(s._str), _refCount(s._refCount) {++(*_refCount);  // 增加引用计数}// 赋值运算符重载String& operator=(const String& s) {if (this != &s) {if (--(*_refCount) == 0) {  // 释放旧资源delete[] _str;delete _refCount;}_str = s._str;_refCount = s._refCount;++(*_refCount);  // 增加引用计数}return *this;}// 析构函数~String() {if (--(*_refCount) == 0) {  // 释放资源delete[] _str;delete _refCount;}}private:char* _str;int* _refCount;  // 引用计数指针
};// 测试函数
void TestString() {String s1("hello bit!!!");String s2(s1);  // 增加引用计数String s3 = s2;  // 增加引用计数
}int main() {TestString();return 0;
}

5.1 写时拷贝

  • 定义:通过引用计数实现资源共享,仅在写操作时进行深拷贝。
  • 操作
    • 每次拷贝时增加引用计数。
    • 只有在实际写操作发生时才进行深拷贝。
小李的理解
  • 写时拷贝:就像兄弟姐妹共享一个玩具,只有在其中一个想要修改玩具时,才会给他一个新的玩具。

5.2 需要记住的知识点

  • 写时拷贝通过引用计数优化资源管理,减少不必要的深拷贝操作。
  • 这种技术在某些情况下能提高性能,但也有复杂性增加和多线程不安全的问题。

6. 总结

实现一个自定义的String类,最重要的是理解和正确实现构造函数、拷贝构造函数、赋值运算符重载和析构函数。通过深拷贝和写时拷贝等技术,可以确保对象管理资源的正确性和高效性。

小李的理解
  • 构造函数:初始化对象,确保资源正确分配。
  • 析构函数:释放资源,避免内存泄漏。
  • 拷贝构造函数:深拷贝确保每个对象有独立资源。
  • 赋值运算符重载:自我赋值检查,深拷贝确保安全赋值。
  • 现代C++:利用swap和临时对象简化代码,实现异常安全。
  • 写时拷贝:优化资源管理,通过引用计数延迟深拷贝操作。

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

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

相关文章

入门PHP就来我这(纯干货)08

~~~~ 有胆量你就来跟着路老师卷起来&#xff01; -- 纯干货&#xff0c;技术知识分享 ~~~~ 路老师给大家分享PHP语言的知识了&#xff0c;旨在想让大家入门PHP&#xff0c;并深入了解PHP语言。 1 PHP对象的高级应用 1.1 final关键字 final 最终的、最后的。被final修饰过的类…

LabVIEW汽车ECU测试系统

开发了一个基于LabVIEW开发的汽车发动机控制单元&#xff08;ECU&#xff09;测试系统。该系统使用了NI的硬件和LabVIEW软件&#xff0c;能够自动执行ECU的功能测试和性能测试&#xff0c;确保其在不同工作条件下的可靠性和功能性。通过自动化测试系统&#xff0c;大大提高了测…

【docker nvidia/cuda】ubuntu20.04安装docker踩坑记录

docker nvidia 1.遇到这个错误&#xff0c;直接上魔法(科学上网) OpenSSL SSL_connect: Could not connect to nvidia.github.io:443 这个error是运行 NVIDIA官方docker安装教程 第一个 curl 命令是遇到的 2. apt-get 更新 sudo apt update遇到 error https://download.do…

CDC实时同步进行时遇到不可抗力中断了怎么办?

目录 一、CDC技术的概念 二、CDC技术的应用场景 1.数据复制和同步 2.实时数据仓库 3.业务过程监控和审计 4.ETL 进程优化 三、CDC与数据管道的关系 1.区别 CDC&#xff08;Change Data Capture&#xff09; 数据管道&#xff08;Data Pipeline&#xff09; 2.联系 CDC是数据管道…

4面体空间5点结构种类与占比

在30个点的4面体中取5个点&#xff0c;有30*29*28*27*26/(5*4*3*2)142506种取法&#xff0c; 这里要求5个点必须是直链或支链。共有496个组合符合要求&#xff0c;按平移对称性可分成181个不同的结构 结构 数量 结构 数量 结构 数量 结构 数量 结构 数量 结构 数量 …

深入分析 Android BroadcastReceiver (九)

文章目录 深入分析 Android BroadcastReceiver (九)1. Android 广播机制的扩展应用与高级优化1.1 广播机制的扩展应用1.1.1 示例&#xff1a;有序广播1.1.2 示例&#xff1a;粘性广播1.1.3 示例&#xff1a;局部广播 1.2 广播机制的高级优化1.2.1 示例&#xff1a;使用 Pending…

【C++】 解决 C++ 语言报错:Double Free or Corruption

文章目录 引言 双重释放或内存破坏&#xff08;Double Free or Corruption&#xff09;是 C 编程中常见且严重的内存管理问题。当程序尝试多次释放同一块内存或对已经释放的内存进行操作时&#xff0c;就会导致双重释放或内存破坏错误。这种错误不仅会导致程序崩溃&#xff0c…

跑腿平台小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;基础数据管理&#xff0c;管理员管理&#xff0c;接单详情管理&#xff0c;跑腿员管理&#xff0c;跑腿任务管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;跑腿任务&#xff0c;接单员&…

HTML如何在图片上添加文字

HTML如何在图片上添加文字 当我们开发一个页面&#xff0c;插入图片时&#xff0c;需要有一组文字对图片进行描述。那么HTML中如何在图片上添加文字呢&#xff1f;这篇文章告诉你。 先让我们来看下效果图&#xff1a; 句子“这是一张夜空图片”被放置在了图片的左下角。 那么…

Wing FTP Server

文章目录 1.Wing FTP Server简介1.1主要特点1.2使用教程 2.高级用法2.1Lua脚本,案例1 1.Wing FTP Server简介 Wing FTP Server&#xff0c;是一个专业的跨平台FTP服务器端&#xff0c;它拥有不错的速度、可靠性和一个友好的配置界面。它除了能提供FTP的基本服务功能以外&#…

空调计费系统是什么,你知道吗

空调计费系统是一种通过对使用空调的时间和能源消耗进行监测和计量来进行费用计算的系统。它广泛应用于各种场所&#xff0c;如家庭、办公室、商场等&#xff0c;为用户提供了方便、准确的能源使用管理和费用控制。 可实现功能 智能计费&#xff1a;中央空调分户计费系统通过智…

【yolov8系列】ubuntu上yolov8的开启训练的简单记录

前言 yolov8的广泛使用&#xff0c;拉取yolov8源码工程&#xff0c;然后配置环境后直接运行&#xff0c;初步验证自己数据的检测效果&#xff0c;在数据集准备OK的情况下 需要信手拈来&#xff0c;以保证开发过程的高效进行。 本篇博客更注意为了方便自己使用时参考。顺便也记录…

Nginx 常用配置与应用

Nginx 常用配置与应用 官网地址&#xff1a;https://nginx.org/en/docs/ 目录 Nginx 常用配置与应用 Nginx总架构 正向代理 反向代理 Nginx 基本配置反向代理案例 负载均衡 Nginx总架构 进程模型 正向代理 反向代理 Nginx 基本配置反向代理案例 负载均衡 Nginx 基本配置…

Linux启动elasticsearch,提示权限不够

Linux启动elasticsearch&#xff0c;提示权限不够&#xff0c;如下图所示&#xff1a; 解决办法&#xff1a; 设置文件所有者&#xff0c;即使用户由权限访问文件 sudo chown -R 用户名[:新组] ./elasticsearch-8.10.4 //切换到elasticsearch-8.10.4目录同级 chown详细格式…

基于SpringBoot的就业信息管理系统

你好&#xff0c;我是计算机学姐码农小野&#xff01;如果你对就业信息管理系统感兴趣或有相关需求&#xff0c;欢迎私信联系我。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; SpringBootMySql 工具&#xff1a; MyEclipse、Tomcat 系统展示…

ChatGPT如何提升论文写作(附指令集合)

先讲前提&#xff1a; ChatGPT无论是3.5还是4.0都存在非常严重的幻觉问题&#xff0c;目前ChatGPT无法替代搜索引擎。 如果你希望得到更加优质的体验&#xff0c;请用GPT-4.0&#xff0c;幻觉问题上比3.5大幅降低 ChatGPT中文版&#xff0c;一站式AI创作平台​aibox365.com …

微信小程序的智慧物流平台-计算机毕业设计源码49796

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3研究方法 1.4开发技术 1.4.1 微信开发者工具 1.4.2 Node.JS框架 1.4.3 MySQL数据库 1.5论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 用户登录流程 2.2.2 数据删除流程 2.3 系统功能分…

为什么英智智能宝能让律师工作事半功倍

大语言模型能够极大提高人们的知识理解能力和知识服务能力&#xff0c;法律服务是典型的知识服务领域&#xff0c;据悉律师有38%的任务都是重复性工作&#xff0c;这些任务有潜力被大模型替代。 但在法律行业中的高度专业且复杂的问题时&#xff0c;通用型大模型的回答虽能提供…

Twitter群发消息API接口的功能?如何配置?

Twitter群发消息API接口怎么申请&#xff1f;如何使用API接口&#xff1f; 为了方便企业和开发者有效地与用户互动&#xff0c;Twitter提供了各种API接口&#xff0c;其中Twitter群发消息API接口尤为重要。AokSend将详细介绍Twitter群发消息API接口的功能及其应用场景。 Twit…

APP渗透-android12夜神模拟器+Burpsuite实现

一、夜神模拟器下载地址&#xff1a;https://www.yeshen.com/ 二、使用openssl转换证书格式 1、首先导出bp证书 2、将cacert.der证书在kali中转换 使用openssl生成pem格式证书,并授予最高权限 openssl x509 -inform der -in cacert.der -out cacert.pem chmod 777 cacert…