【C++指南】string(二):深入探究 C++ `basic_string`:成员变量、函数全解析

【C++指南】string(二):深入探究 C++ `basic_string`:成员变量、函数全解析
.💓 博客主页:倔强的石头的ZEEKLOG主页
📝Gitee主页:倔强的石头的gitee主页
⏩ 文章专栏:《C++指南》
期待您的关注

文章目录

    • 引言
    • `basic_string` 的成员变量
      • 内部结构概述
      • 示例代码推测成员变量
    • 默认成员函数
      • 构造函数
      • 析构函数
      • 赋值运算符重载
    • 迭代器
      • 迭代器类型
      • 迭代器的使用规则
    • 容量管理
      • 容量相关函数
      • 容量管理规则
    • 修改操作
      • 插入操作
      • 删除操作
      • 追加操作
      • 修改操作规则
    • 其他相关函数
      • 查找函数
      • 替换函数
      • 比较函数
    • 总结

引言

在第一篇文章中【C++指南】string(一):string从入门到掌握,我们对 C++ 中 string 的起源、basic_string 模板类以及相关字符串类型有了初步的了解。

本文将深入剖析 basic_string 的成员变量、默认成员函数、迭代器、容量管理、修改操作等各类成员函数,详细介绍它们的使用方法、功能特点以及遵循的规则。

basic_string 的成员变量

内部结构概述

basic_string 类模板通常包含几个关键的成员变量来管理字符串数据,虽然具体实现可能因编译器而异,但一般会有以下几个核心部分:

  • 字符存储指针:指向存储字符串字符的动态分配内存区域。
  • 字符串长度:表示当前字符串中实际字符的数量。
  • 容量:表示当前分配的内存空间能够容纳的字符数量(包括字符串结束符)。

示例代码推测成员变量

虽然标准库没有公开 basic_string 的成员变量,但我们可以通过模拟实现来推测其可能的结构:

template<typenameCharT,typenameTraits= std::char_traits<CharT>,typenameAllocator= std::allocator<CharT>>classbasic_string{private: CharT* _data;// 字符存储指针 size_t _size;// 字符串长度 size_t _capacity;// 容量// 其他可能的成员变量和实现细节};

默认成员函数

构造函数

basic_string 提供了多种构造函数重载,以满足不同的初始化需求。

在这里插入图片描述
  • 默认构造函数:创建一个空字符串。
#include<iostream>#include<string>intmain(){ std::string str;// 默认构造,创建空字符串 std::cout <<"Empty string: "<< str << std::endl;return0;}
  • 带字符串字面量的构造函数:使用字符串字面量初始化字符串。其中这个构造函数是日常中最常用的
std::string str("Hello, World!"); std::cout <<"Initialized with literal: "<< str << std::endl;
  • 带重复字符的构造函数:使用指定字符重复多次初始化字符串。
std::string str(5,'a');// 初始化为 "aaaaa" std::cout <<"Repeated characters: "<< str << std::endl;
  • 拷贝构造函数:创建一个新字符串,其内容是另一个字符串的副本。
std::string original("Original"); std::string copy(original); std::cout <<"Copied string: "<< copy << std::endl;

析构函数

析构函数负责在字符串对象生命周期结束时释放其占用的内存资源,防止内存泄漏。在使用 std::string 时,我们无需手动管理内存,析构函数会自动完成这些工作。

{ std::string str("Temporary");// 当 str 离开作用域时,析构函数自动调用}

赋值运算符重载

赋值运算符用于将一个字符串的值赋给另一个字符串。

在这里插入图片描述
std::string source("Source"); std::string destination; destination = source; std::cout <<"Assigned string: "<< destination << std::endl;

迭代器

迭代器类型

basic_string 支持多种迭代器类型,用于遍历字符串中的字符。

  • 正向迭代器begin()end() 分别返回指向字符串起始和结束位置(最后一个字符的下一个位置)的迭代器。
std::string str("Iterate");for(auto it = str.begin(); it != str.end();++it){ std::cout <<*it <<" ";} std::cout << std::endl;
  • 反向迭代器rbegin()rend() 分别返回指向字符串末尾和起始位置(第一个字符的前一个位置)的反向迭代器。
for(auto rit = str.rbegin(); rit != str.rend();++rit){ std::cout <<*rit <<" ";} std::cout << std::endl;
  • 常量迭代器cbegin()cend()crbegin()crend() 用于遍历常量字符串,确保不会修改字符串内容。
const std::string constStr("Constant");for(auto cit = constStr.cbegin(); cit != constStr.cend();++cit){ std::cout <<*cit <<" ";} std::cout << std::endl;

迭代器的使用规则

  • 迭代器可以进行递增(++)和递减(--)操作,用于移动到下一个或前一个字符位置。
  • 可以使用 * 运算符解引用迭代器,获取当前指向的字符。
  • 在使用迭代器时,要确保迭代器的有效性,避免越界访问。

容量管理

容量相关函数

  • size()length():返回字符串中当前存储的字符个数,这两个函数功能相同。
  • 一般我们都会选择使用size函数,因为size函数在C++中的其他容器中也是通用的,只有length函数是因为历史发展原因string所独有的
std::string str("Capacity"); std::cout <<"Size: "<< str.size()<<", Length: "<< str.length()<< std::endl;
  • capacity():返回字符串当前已分配的内存空间能够容纳的字符个数,通常大于或等于 size()
std::cout <<"Capacity: "<< str.capacity()<< std::endl;
  • reserve():预先分配一定大小的内存空间,避免在字符串增长过程中频繁的内存重新分配,提高性能。
str.reserve(20); std::cout <<"Reserved capacity: "<< str.capacity()<< std::endl;
  • resize():改变字符串的长度。
  • 若新长度小于原长度,则会截断字符串;
  • 若新长度大于原长度,会在字符串末尾填充指定字符(默认为空字符);
  • 若新长度大于string容量,则会扩容,并在补充的部分添加指定字符
str.resize(3); std::cout <<"Resized string: "<< str << std::endl; str.resize(5,'x'); std::cout <<"Resized and filled: "<< str << std::endl;

容量管理规则

  • 当字符串长度超过当前容量时,basic_string 会自动重新分配更大的内存空间,并将原有字符复制到新的内存区域。
  • reserve() 只是预先分配内存,不会改变字符串的长度。
  • resize() 会直接改变字符串的长度,可能会导致内存重新分配。

修改操作

插入操作

一般我们用的最多的还是 operator+=,相当于尾插,而insert和erase非必要尽量不用,因为前插涉及到挪动数据,会存在效率的问题

insert() 函数用于在字符串的指定位置插入字符或字符串。

std::string str("Insert"); str.insert(2,"abc");// 在位置 2 插入 "abc" std::cout <<"Inserted string: "<< str << std::endl;

删除操作

erase() 函数用于删除字符串中指定位置或范围的字符。

str.erase(2,3);// 从位置 2 开始删除 3 个字符 std::cout <<"Erased string: "<< str << std::endl;

追加操作

  • push_back():在字符串末尾添加一个字符。
str.push_back('!'); std::cout <<"Pushed back: "<< str << std::endl;
  • append()operator+=:用于在字符串末尾追加字符或字符串。
str.append(" World"); std::cout <<"Appended string: "<< str << std::endl; str +="!"; std::cout <<"Appended with +=: "<< str << std::endl;

修改操作规则

  • 插入和删除操作可能会导致内存重新分配和字符移动,影响性能。
  • 追加操作通常比插入操作更高效,因为它只在字符串末尾进行操作。

其他相关函数

查找函数

  • find():在字符串中查找指定的字符或子串,返回其第一次出现的位置,如果未找到则返回 std::string::npos
std::string str("Find me"); size_t pos = str.find("me");if(pos != std::string::npos){ std::cout <<"Found at position: "<< pos << std::endl;}else{ std::cout <<"Not found"<< std::endl;}
  • rfind():从字符串末尾开始查找,返回最后一次出现的位置。

替换函数

replace() 用于将字符串中指定范围的字符替换为其他字符或子串。

str.replace(0,4,"Replace"); std::cout <<"Replaced string: "<< str << std::endl;

比较函数

compare() 用于比较两个字符串的大小,返回一个整数表示比较结果。

std::string str1("Hello"); std::string str2("World");int result = str1.compare(str2);if(result <0){ std::cout << str1 <<" is less than "<< str2 << std::endl;}elseif(result >0){ std::cout << str1 <<" is greater than "<< str2 << std::endl;}else{ std::cout << str1 <<" is equal to "<< str2 << std::endl;}

总结

本文详细介绍了 C++ basic_string 的成员变量、默认成员函数、迭代器、容量管理、修改操作以及其他相关函数。通过深入了解这些内容,我们可以更加灵活和高效地使用 std::string 及其相关类型。在实际编程中,合理运用这些函数可以提高代码的可读性和性能,避免常见的错误和问题。
后续我们还将进一步探讨 basic_string 的底层实现和一些高级应用场景。

敬请期待下文!

Read more

配置Cursor 编辑器来高效编写 C++ 项目

配置 Cursor 编辑器来高效编写 C++ 项目需要一些关键设置和插件支持。以下是详细步骤: 1. 安装 Cursor * 从官网 https://www.cursor.so 下载并安装适合你系统的版本(Windows/macOS/Linux)。 2. 配置 C++ 开发环境 (1)安装 C++ 编译工具链 * Windows: 安装 MinGW-w64 或 MSVC(通过 Visual Studio 安装)。 * 先打开网址Pre-built Toolchains - mingw-w64https://www.mingw-w64.org/downloads/ 在左侧导航栏选择downloads,选择编译好的安装包,在上图显示的列表框里选择适合自己开发环境的安装包,点击后一般会跳转到github,然后选择合适的版本下载即可。 各版本区别可以通过deepsee大模型查询。 按照后解压,

By Ne0inhk
【Linux/C++多进程篇(二) 】万字解析从“传纸条”到“建仓库”:一文读懂linux系统编程之进程间通信 (IPC)

【Linux/C++多进程篇(二) 】万字解析从“传纸条”到“建仓库”:一文读懂linux系统编程之进程间通信 (IPC)

⭐️在这个怀疑的年代,我们依然需要信仰。 个人主页:YYYing. ⭐️Linux/C++进阶系列专栏:【从零开始的linux/c++进阶编程】 系列上期内容:【Linux/C++多进程篇(一) 】C/C++ 程序中神奇的“分身术” 系列下期内容:【Linux/C++多线程篇(一) 】多线程编程入门 目录 前言: 进程间通信(IPC) 一、进程间通信的基础概念 二、内核提供的通信方式 2.1、无名管道  📖 无名管道的API  📖 代码案例 2.2、有名管道  📖 有名管道的API  📖 代码案例 2.3、管道特点 2.4、信号  📖 信号相关概念

By Ne0inhk
【C++笔记】类与对象(进阶)

【C++笔记】类与对象(进阶)

前言:           在前文中,我们已经系统地学习了类与实例化对象的概念定义、语法结构和核心特性。本文将深入探讨类与对象的默认成员函数,其中以下四个方面最为关键:构造函数、拷贝构造函数、析构函数以及操作符重载。                  一、类的默认成员函数          定义:默认成员函数就是用户没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。                  在⼀个类中,如果我们不显示编写的情况下,编译器会默认⽣成以下4个重要的默认成员函数:          默认成员函数是C++中重要且复杂的知识点,需要从两个维度进行掌握:          ①了解编译器自动生成的默认函数行为及其适用性          ②当编译器自动生成的默认函数无法满足需求时,掌握自定义实现的方法                   二、构造函数          什么是构造函数?                  你可以把构造函数想象成产品的“出厂设置”,当你根据图纸(类)生产出一个新零件(对象)时,构造函数

By Ne0inhk

OSGEarth 在 Qt C++ 中显示三维地球经纬度

OSGEarth 在 Qt C++ 中显示三维地球经纬度 概述 本文介绍如何在 Qt C++ 项目中集成 OSGEarth,并实现鼠标交互获取和显示三维地球表面的经纬度坐标。 环境要求 * Qt 5.12+ 或 Qt 6.x * OSGEarth 3.x * OpenSceneGraph (OSG) 3.6+ * C++11 或更高版本 核心功能实现 1. 项目配置 首先在 .pro 文件中添加必要的库: QT += core gui widgets opengl CONFIG += c++11 # OSG 和 OSGEarth 库配置 INCLUDEPATH += /usr/

By Ne0inhk