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

C++深入学习string类成员函数(1):默认与迭代

引言

在 C++ 编程中,std::string 类是处理字符串的核心工具之一。作为一个动态管理字符数组的类,它不仅提供了丰富的功能,还通过高效的内存管理和操作接口,极大地方便了字符串操作。通过深入探讨 std::string 的各类成员函数,我们将更加全面地理解它背后的机制和使用场景。

在本系列博客中,我们将详细剖析 std::string 的各类成员函数,带你深入理解 C++ 中字符串的操作与管理。以下内容均是在c++11标准版本的介绍。

1.默认成员函数

1.1string类的构造函数(Construct)

1.1.1函数原型

在C++中,std::string 是标准库提供的一个字符串类,它提供了多种构造函数来创建字符串对象。构造基本语法如下:

public member function
std::string::stringdefault (1)	       string();copy (2)	       string (const string& str);from c-string (3)  string (const char* s);from sequence (4)  string (const char* s, size_t n);fill (5)	       string (size_t n, char c);substring (6)	   string (const string& str, size_t pos, size_t len = npos);range (7)	       template <class InputIterator>string  (InputIterator first, InputIterator last);initializer list (8)	string (initializer_list<char> il);move (9)	       string (string&& str) noexcept;

1.1.2 noexcept

noexcept是c++11引入的关键字,用来表明不会抛出异常,它在函数声明中使用,告诉编译器和程序员该函数在运行时不会引发异常。

(1)noexcept 的作用:

优化性能:编译器可以利用 noexcept 进行优化。如果编译器知道某个函数不会抛出异常,它可以避免生成一些与异常处理相关的代码,从而提高性能。

提高代码安全性:当你明确声明某个函数不会抛出异常,调用者可以放心地使用该函数,而不需要担心异常的传播和处理。

异常安全保障:当你编写不应该抛出异常的函数时,使用 noexcept 明确表达这种意图,防止由于代码错误导致异常意外抛出。

(2)使用场景

移动构造函数和移动赋值运算符:对于某些类型的对象,移动操作(如移动构造函数、移动赋值运算符)通常是 noexcept 的。这是因为在某些容器(如 std::vector)中,出于性能考虑,当元素在容器内部移动时,要求这些操作不会抛出异常。

异常安全的保证:如果你的函数不打算抛出异常,最好明确使用 noexcept 进行标记,提升代码的可读性和可维护性。

1.1.3深入解析

(1) 默认构造函数
创建一个空字符串对象。

std::string str;

此时,`str` 是一个空字符串。

(2)拷贝构造函数
通过另一个 `std::string` 对象来构造字符串。

 string (const string& str);std::string str1 = "Hello";
std::string str2 = str1; // 使用str1来构造str2

(3)从 C 字符串构造
使用 C 风格的字符串(即字符数组)来构造 `std::string` 对象。

string (const char* s);const char* cstr = "Hello";
std::string str(cstr);

(4)从 C 字符串的部分字符构造
可以指定从 C 字符串中提取的字符个数。

string (const char* s, size_t n);const char* cstr = "Hello, World!";
std::string str(cstr, 5); // 只提取前5个字符,即"Hello"

(5)从字符构造
可以指定使用某个字符构造一个指定长度的字符串。

 string (size_t n, char c);std::string str(5, 'A'); // 构造一个包含5个'A'字符的字符串 "AAAAA"

(6)从子字符串开始构造

 可以从现有的std::string对象中提取一个子字符串来构造新的std::string。pos是子字符串的起始位置,len表示要提取的字符数(默认为npos,表示从起始位置到字符串末尾)。

string (const string& str, size_t pos, size_t len = npos);  std::string original = "Hello, World!";// 从位置7开始,提取5个字符构造子字符串std::string subStr(original, 7, 5);// 输出 "World"

(7)从迭代器范围构造
可以使用迭代器范围来构造字符串,例如从数组或其他容器中提取内容。

 template <class InputIterator>string  (InputIterator first, InputIterator last);std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'};
std::string str(vec.begin(), vec.end()); // 构造 "Hello"

(8)初始化构造列表(C++11及更高版本)

std::string 的 initializer list 构造函数允许你使用一个 初始化列表(std::initializer_list<char>)直接初始化一个字符串对象。

string (initializer_list<char> il);std::string str = {'H', 'e', 'l', 'l', 'o'};std::cout << "str: " << str << std::endl;  // 输出 "Hello"

(9)移动构造函数 (C++11及更高版本)
可以利用移动语义,从一个临时的 `std::string` 对象中转移资源,而不需要复制。

string (initializer_list<char> il);std::string str1 = "Hello";
std::string str2 = std::move(str1); // str2获得str1的资源,str1被置为空

总结
`std::string` 的构造方式灵活多样,可以从字符数组、部分字符、字符迭代器等多种来源构造。此外,在C++11及以上版本中,`std::string` 还支持移动构造,进一步优化了性能。

1.2赋值运算符重载(operator=)

1.2.1函数原型:

   string (1)         string& operator= (const string& str);c-string (2)	      string& operator= (const char* s);
character (3)	      string& operator= (char c);
initializer list (4)  string& operator= (initializer_list<char> il);move (5)	      string& operator= (string&& str) noexcept;

1.2.2深入解析 

(1)拷贝赋值运算符

拷贝赋值运算符用于将一个 `std::string` 对象赋值给另一个 `std::string` 对象。

string& operator= (const string& str);std::string str1 = "Hello";std::string str2;str2 = str1;  // 使用拷贝赋值运算符std::cout << "str1: " << str1 << std::endl;  // 输出 "Hello"std::cout << "str2: " << str2 << std::endl;  // 输出 "Hello"

(2)C 风格字符串赋值运算符

用于将从风格的字符串(字符数组指针)赋值给std::string对象

string& operator= (const char* s);const char* cStr = "Hello, World!";std::string str;str = cStr;  // 使用C风格字符串赋值运算符std::cout << "str: " << str << std::endl;  // 输出 "Hello, World!"

(3)字符赋值运算符

用于将一个字符赋值给 `std::string` 对象,将该字符作为字符串的唯一字符。

string& operator= (char c);char c = 'A';std::string str;str = c;  // 使用字符赋值运算符std::cout << "str: " << str << std::endl;  // 输出 "A"

(4)初始化列表赋值运算符

用于通过 C++11 提供的初始化列表,将多个字符赋值给 `std::string` 对象。

string& operator= (std::initializer_list<char> il);std::string str;str = {'H', 'e', 'l', 'l', 'o'};  // 使用初始化列表赋值运算符std::cout << "str: " << str << std::endl;  // 输出 "Hello"

(5)移动赋值运算符

用于将一个临时或即将被销毁的 `std::string` 对象的内容移动到当前对象,而不是复制。

string& operator= (string&& str) noexcept;string str1 = "hello";string str2;str2 = std::move(str1);cout << str1 << endl; // str1 可能为空或处于未定义状态cout << str2 << endl;// 输出 "Hello"

1.2.3总结

- `string& operator=(const string& str)`:将一个 `std::string` 对象赋值给另一个。
- `string& operator=(const char* s)`:将 C 风格字符串赋值给 `std::string`。
- `string& operator=(char c)`:将一个字符赋值给 `std::string`,该字符成为字符串的唯一字符。
- `string& operator=(initializer_list<char> il)`:使用初始化列表赋值多个字符。
- `string& operator=(string&& str) noexcept`:使用移动赋值运算符,将一个临时对象的内容移动到当前对象。

这些赋值运算符提供了不同的赋值方式,极大地增强了 `std::string` 的灵活性。

2.返回迭代器的成员函数

在 C++中,迭代器是一种对象,它能够用来遍历容器中的元素。迭代器提供了一种统一的方式来访问不同类型容器中的元素,而无需了解容器的内部实现细节。这里如果对迭代器不太了解,可以去看这篇博客C++标准库类——string类-CSDN博客。

std::string 提供了一系列返回迭代器的成员函数,用于遍历和操作字符串中的字符。通过这些迭代器,您可以轻松地访问、修改和遍历字符串中的每个字符。常见的迭代器包括正向迭代器、常量迭代器、反向迭代器以及它们的常量版本

2.1正向迭代器(iterator)

(1)begin()

- begin():返回指向字符串首个字符的迭代器。

      iterator begin() noexcept;
const_iterator begin() const noexcept;

 - iterator begin() noexcept 返回一个可修改的迭代器,指向字符串的第一个字符。

 - const_iterator begin() const noexcept 返回一个常量迭代器,指向字符串的第一个字符,且不允许通过该迭代器修改字符串内容。 

(2)end()

- end():返回指向字符串末尾(即最后一个字符的下一个位置)的迭代器

 iterator end() noexcept;
const_iterator end() const noexcept;

- iterator end()返回一个可修改的迭代器,指向字符串末尾的下一个位置。
- const_iterator end() const noexcept返回一个常量迭代器,指向末尾的下一个位置,且不允许通过该迭代器修改字符串内容

(3)示例

#include <iostream>
using namespace std;int main()
{//使用非const迭代器遍历并修改字符string st1 = "Hello, henu";string::iterator it1 = st1.begin();while (it1 != st1.end()){if (*it1 == ',')*it1 = ';';it1++;}cout << st1 << endl;//Hello; henu//使用const迭代器遍历,但不能修改字符const string st2 = "Hello, world";string::const_iterator it2 = st2.begin();while (it2 != st2.end()){cout << *it2;//Hello, worldit2++;}return 0;
}

(4)常量版本

- cbegin():返回指向字符串首个字符的常量迭代器。

const_iterator cbegin() const noexcept;

- cend():返回指向字符串末尾的常量迭代器。

const_iterator cend() const noexcept;

常量版本其实就是与上面返回常量迭代器的声明类型的作用是相同的,在此不再赘述。

2. 2反向迭代器(reverse_iterator)

(1)rbegin()

- rbegin():返回指向字符串末尾(即最后一个字符)的反向迭代器。

 reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;

- reverse_iterator rbegin() 返回一个可修改的反向迭代器,指向字符串的最后一个字符。 

- const_reverse_iterator rbegin() const noexcept 返回一个常量反向迭代器,指向字符串的最后一个字符,且不允许通过该迭代器修改字符串内容

(2)rend()

- rend():返回指向字符串首个字符的前一个位置的反向迭代器。

 reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;

- reverse_iterator rend() 返回一个可修改的反向迭代器,指向第一个元素之前的位置。

- const_reverse_iterator rend() const noexcept 返回一个常量反向迭代器,指向第一个元素之前的位置,且不允许通过该迭代器修改字符串内容。 

(3)示例

#include <iostream>
using namespace std;int main()
{//使用 reverse_iterator遍历并修改字符string st1 = "Hello, world";//auto it1 = st1.rbegin();string::reverse_iterator it1 = st1.rbegin();while (it1 != st1.rend()){if (*it1 == ',')*it1 = ';';cout << *it1;it1++;//注意,这里用++,而不是--}cout << endl;//使用 const_reverse_iterator遍历并修改字符const string st2 = "Hello, henu";//auto it2 = st2.rbegin();string::const_reverse_iterator it2 = st2.rbegin();//string::const_reverse_iterator it2 = st2.crbegin();while (it2 != st2.rend())//while (it2 != st2.crend()){cout << *it2;it2++;}return 0;
}

(4)常量版本:

- crbegin():返回指向字符串末尾的常量反向迭代器。

const_reverse_iterator crbegin() const noexcept

- crend():返回指向字符串首个字符的前一个位置的常量反向迭代器。

const_reverse_iterator crend() const noexcept;

这里的常量版本同样与上面返回常量迭代器的声明的类型的作用相同,不再赘述。

2.3总结

- begin():正向迭代器,指向首个字符。
- end():正向迭代器,指向末尾后的位置。
- rbegin():反向迭代器,指向最后一个字符。
- rend():反向迭代器,指向第一个字符之前的位置。
- cbegin():常量正向迭代器,指向首个字符。
- cend():常量正向迭代器,指向末尾后的位置。
- crbegin():常量反向迭代器,指向最后一个字符。
- crend():常量反向迭代器,指向第一个字符之前的位置。 

更多string类的成员函数:string - C++ Reference (cplusplus.com)

 

相关文章:

C++深入学习string类成员函数(1):默认与迭代

引言 在 C 编程中&#xff0c;std::string 类是处理字符串的核心工具之一。作为一个动态管理字符数组的类&#xff0c;它不仅提供了丰富的功能&#xff0c;还通过高效的内存管理和操作接口&#xff0c;极大地方便了字符串操作。通过深入探讨 std::string 的各类成员函数&#…...

DataGrip远程连接Hive

学会用datagrip远程操作hive 连接前提条件&#xff1a; 注意&#xff1a;mysql是否是开启状态 启动hadoop集群 start-all.sh 1、启动hiveserver2服务 nohup hiveserver2 >> /usr/local/soft/hive-3.1.3/hiveserver2.log 2>&1 & 2、beeline连接 beelin…...

go 读取excel

一、安装依赖 go get github.com/tealeg/xlsx二、main.go package mainimport "fmt" import "github.com/tealeg/xlsx"type Student struct {Name stringSex string }func (student Student) show() {fmt.Printf("Name:%s Sex:%s\r\n", stude…...

Linux进阶系列(四)——awk、sed、端口管理、crontab

目录 1. 写在前面2. awk —— 强大的文本处理工具2.1 awk 概述2.2 awk 脚本结构2.3 awk 的内置变量2.4 awk 的高级用法2.5 awk实践 3. sed —— 流式文本编辑器3.1 sed 的基本语法3.2 sed 常用命令3.3 sed 的高级用法 4. Linux 端口管理4.1 端口的概念4.2 查看端口状态4.3 开放…...

利用Metasploit进行信息收集与扫描

Metasploit之信息收集和扫描 在本文中&#xff0c;我们将学习以下内容 使用Metasploit被动收集信息 使用Metasploit主动收集信息 使用Nmap进行端口扫描 使用db_nmap方式进行端口扫描 使用ARP进行主机发现 UDP服务探测 SMB扫描和枚举 SSH版本扫描 FTP扫描 SMTP枚举 …...

基于Pytorch框架的深度学习MODNet网络精细人像分割系统源码

第一步&#xff1a;准备数据 人像精细分割数据&#xff0c;可分割出头发丝&#xff0c;为PPM-100开源数据 第二步&#xff1a;搭建模型 MODNet网络结构如图所示&#xff0c;主要包含3个部分&#xff1a;semantic estimation&#xff08;S分支&#xff09;、detail prediction…...

Go语言中的并发编程

Go语言中的并发编程Go语言中的并发编程主要依赖于两个核心概念&#xff1a;goroutine 和 channel。1. Goroutinegoroutine 的特点结束 goroutine2. Channel创建 Channel发送和接收数据Channel 的类型使用 select 语句简单的多个 goroutine使用 WaitGroup 等待所有 goroutine 完…...

python学习笔记(3)——控制语句

控制语句 我们在前面学习的过程中&#xff0c;都是很短的示例代码&#xff0c;没有进行复杂的操作。现在&#xff0c;我们将开始学习流程控制语句。 前面学习的变量、数据类型&#xff08;整数、浮点数、布尔&#xff09;、序列&#xff08;字符串、列表、元组、字 典、集合&am…...

关系数据库设计之Armstrong公理详解

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、Armstrong公理简介 Armstrong公理是一组在关系数据库理论中用于推导属性依赖的基本规则。这些公理是以著名计算机科学家威廉阿姆斯特朗&…...

【Geoserver使用】SRS处理选项

文章目录 前言一、Geoserver的三种SRS处理二、对Bounding Boxes计算的影响总结 前言 今天来看看Geoserver中发布图层时的坐标参考处理这一项。根据Geoserver官方文档&#xff0c;坐标参考系统 (CRS) 定义了地理参考空间数据与地球表面实际位置的关系。CRS 是更通用的模型&…...

python里面的单引号和双引号的区别

在Python中&#xff0c;单引号&#xff08;‘’&#xff09;和双引号&#xff08;“”&#xff09;在大多数情况下是等价的&#xff0c;没有本质区别。它们都用于创建字符串。以下是一些关键点&#xff1a; 功能相同&#xff1a; 两者都可以用来定义字符串&#xff0c;例如&…...

为什么不要在循环,条件或嵌套函数中调用hooks

为什么不要在循环&#xff0c;条件或嵌套函数中调用hooks 前言useState Hook 的工作原理具体实现1、初始化2、第一次渲染3、后续渲染4、事件处理简单代码实现 为什么顺序很重要Bad Component 第一次渲染Bad Component 第二次渲染 总结 前言 自从 React 推出 hooks 的 API 后&a…...

将成功请求的数据 放入apipost接口测试工具,发送给后端后,部分符号丢失

将成功请求的数据 放入apipost接口测试工具&#xff0c;发送给后端后&#xff0c;部分符号丢失 apipost、接口测试、符号、丢失、错乱、变成空格背景 做CA对接&#xff0c;保存CA系统的校验数据&#xff0c;需要模仿前端请求调起接口&#xff0c;以便测试功能完整性。 问题描…...

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…...

vue3 数字滚动组件封装

相关参考文献 干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React) Vue3 插件方式 安装插件: countup.js 封装组件: components/count-up/index.js <template><div class="countup-wrap"><slot name="prefix"></slot&g…...

如何确保消息只被消费一次:Java实现详解

引言 在分布式系统中&#xff0c;消息传递是系统组件间通信的重要方式&#xff0c;而确保消息在传递过程中只被消费一次是一个关键问题。如果一个消息被多次消费&#xff0c;可能会导致业务逻辑重复执行&#xff0c;进而产生数据不一致、错误操作等问题。特别是在金融、电商等…...

Web3技术在元宇宙中的应用:从区块链到智能合约

随着元宇宙的兴起&#xff0c;Web3技术正逐渐成为其基础&#xff0c;推动着数字空间的重塑。元宇宙不仅是一个虚拟世界&#xff0c;它还代表着一个由去中心化技术驱动的新生态系统。在这个系统中&#xff0c;区块链和智能合约发挥着至关重要的作用&#xff0c;为用户提供安全、…...

关于QSizeGrip在ui界面存在布局的情况下的不显示问题

直接重写resizeEvent你会发现&#xff1a;grip并没有显示 void XXXXX::resizeEvent(QResizeEvent *event) {QWidget::resizeEvent(event);this->m_sizeGrip->move(this->width() - this->m_sizeGrip->width() - 3,this->height() - this->m_sizeGrip->…...

开始场景的制作+气泡特效的添加

3D场景或2D场景的切换 1.新建项目时选择3D项目或2D项目 2.如下图操作&#xff1a; 开始前的固有流程 按照如下步骤进行操作&#xff0c;于步骤3中更改Company Name等属性&#xff1a; 本案例分辨率可以如下设置&#xff0c;有能力者可根据需要自行调整&#xff1a; 场景制作…...

位运算--(二进制中1的个数)

位运算是计算机科学中一种高效的操作方式&#xff0c;常用于处理二进制数据。在Java中&#xff0c;位运算通常通过位移操作符和位与操作符实现。 当然位运算还有一些其他的奇淫巧计&#xff0c;今天介绍两个常用的位运算方法&#xff1a;返回整数x的二进制第k位的值和返回x的最…...

使用Docker和Macvlan驱动程序模拟跨主机跨网段通信

以下是使用Docker和Macvlan驱动程序模拟跨主机跨网段通信的架构图&#xff1a; #mermaid-svg-b7wuGoTr6eQYSNHJ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-b7wuGoTr6eQYSNHJ .error-icon{fill:#552222;}#mermai…...

RestCloud webservice 流程设计

RestCloud webservice 流程设计 操作步骤 离线数据集成&#xff08;首页&#xff09; → \rightarrow → 示例应用数据集成流程&#xff08;边栏&#xff09; → \rightarrow → 所有数据流程 → \rightarrow → webservice节点获取城市列表 → \rightarrow → 流程设计 …...

从入门到精通:QT 100个关键技术关键词

Qt基础概念 Qt Framework - 一个跨平台的C图形用户界面应用程序开发框架。它不仅提供了丰富的GUI组件&#xff0c;还包括网络、数据库访问、多媒体支持等功能。 Qt Creator - Qt官方提供的集成开发环境&#xff08;IDE&#xff09;&#xff0c;集成了代码编辑器、项目管理工具、…...

2024年双十一值得入手的好物有哪些?五大性价比拉满闭眼入好物盘点

随着2024年双十一购物狂欢节的临近&#xff0c;消费者们纷纷开始关注各类好物&#xff0c;期待在这一天能够以最优惠的价格入手心仪的商品&#xff0c;在这个特殊的时刻&#xff0c;我们为大家盘点了五大性价比拉满的闭眼入好物&#xff0c;这些产品不仅品质卓越&#xff0c;而…...

Hbase日常运维

1 Hbase日常运维 1.1 监控Hbase运行状况 1.1.1 操作系统 1.1.1.1 IO 群集网络IO&#xff0c;磁盘IO&#xff0c;HDFS IO IO越大说明文件读写操作越多。当IO突然增加时&#xff0c;有可能&#xff1a;1.compact队列较大&#xff0c;集群正在进行大量压缩操作。 2.正在执行…...

鸿蒙开发的基本技术栈及学习路线

随着智能终端设备的不断普及与技术的进步&#xff0c;华为推出的鸿蒙操作系统&#xff08;HarmonyOS&#xff09;迅速引起了全球的关注。作为一个面向多种设备的分布式操作系统&#xff0c;鸿蒙不仅支持手机、平板、智能穿戴设备等&#xff0c;还支持IoT&#xff08;物联网&…...

【算法】反向传播算法

David Rumelhart 是人工智能领域的先驱之一&#xff0c;他与 James McClelland 等人在1986年通过其著作《Parallel Distributed Processing: Explorations in the Microstructure of Cognition》详细介绍了反向传播算法&#xff08;Backpropagation&#xff09;&#xff0c;这一…...

外贸非洲市场要如何开发

刚不久前中非合作峰会论坛之后&#xff0c;取消了非洲33国的进口关税&#xff0c;中非贸易一直以来都还不错&#xff0c;这次应该会更上一个台阶。今天就来给大家分享一下&#xff0c;关于非洲市场的一些分析和开发方法。 一、非洲市场情况 非洲是一个广阔的大陆&#xff0c;由…...

python去除空格join()

sinput().split() print( .join(s)) input().split()的作用&#xff1a; split()是字符串对象的方法。当对一个字符串调用split()方法时&#xff0c;它会根据指定的分隔符将字符串分割成多个子字符串&#xff0c;并将这些子字符串以列表的形式返回。如果不指定分隔符&#xf…...

git push错误:Out of memory, malloc failed (tried toallocate 947912704 bytes)

目录 一、错误截图 二、解决办法 一、错误截图 因项目文件过大&#xff0c;http.postBuffer设置的内存不够&#xff0c;所以报错。 二、解决办法 打开cmd窗口&#xff0c;执行如下命令即可 git config --global http.postBuffer 1024000000 如图所示 执行完成以后&#…...