C++17中std::string_view的使用

news2024/12/25 13:52:12

      为了解决std::string初始化(或拷贝)成本高昂的问题,C++17引入了std::string_view。std::string_view提供对现有字符串(C风格字符串、std::string、或另一个std::string_view)的只读访问,而无需进行拷贝。当想要有效地处理和操作字符串而不修改它们时,通常使用std::string_view。

int test_string_view_copy()
{
	std::string str1{ "china" };
	std::string_view strv1{ "beijing" };

	// str2和str1的数据存放在完全不同的两个位置(副本); strv2和strv1的数据都指向同一个指针地址,没有额外的拷贝(副本)
	std::string str2{ str1 };
	std::string_view strv2{ strv1 };
	std::cout << "str2: " << str2 << ", strv2: " << strv2 << "\n"; // str2: china, strv2: beijing

	str1.clear();
	strv1 = {}; //strv1 = strv1.substr(0, 0); //strv1.remove_prefix(strv1.size()); // 注意它们的区别
	// clear str1完全不会影响到str2; "clear" strv1也不会影响到strv2,因为strv2指向的指针地址没有变,对strv1 "clear"操作并不会影响到它之前指向的指针地址数据
	std::cout << "str2: " << str2 << ", strv2: " << strv2 << "\n"; // str2: china, strv2: beijing

	return 0;
}

      std::string为模板类std::basic_string<char>,而std::string_view为模板类std::basic_string_view<char>。如下,其中CharT为character type。

template<class CharT,
    class Traits = std::char_traits<CharT>,
    class Allocator = std::allocator<CharT> >
class basic_string;

template<class CharT,
    class Traits = std::char_traits<CharT> >
class basic_string_view;

using string      = basic_string<char>;
using string_view = basic_string_view<char>;

      模板类std::basic_string的声明参考:     https://en.cppreference.com/w/cpp/header/string
      模板类std::basic_string_view的声明参考:https://en.cppreference.com/w/cpp/header/string_view
      std::basic_string有析构函数,而std::basic_string_view没有析构函数

      std::string_view优点
      1.轻便:主要用于提供字符串的视图(view),使std::string_view拷贝字符串的过程非常高效,永远不会创建字符串的任何副本,不像std::string会效率低下且导致内存开销。std::string_view不拥有字符串数据,它仅提供对现有字符串的视图或引用(view or reference)。这使得它适合需要访问或处理字符串而无需内存分配或重新分配开销的场景.
      2.轻量高效:由于std::string_view不管理内存,因此它具有最小的内存占用。分配或拷贝std::string_view既快速又便宜,因为它只涉及拷贝字符串的引用、长度和起始位置。
      3.更好的性能:std::string_view比const std::string&更好,因为它消除了在字符串的最开头有一个std::string对象的约束,因为std::string_view由两个元素组成:第一个是const char*,指向数组的起始位置,第二个是size
      4.std::string_view提供了std::string提供的成员函数的子集,主要集中于只读操作。虽然你可以访问字符并执行搜索,但无法修改std::string_view的内容。这种不变性确保了操作的安全性,并保证所查看的字符串保持不变。

      注意
      1.与C字符串和std::string在字符串末尾需要字符串终止符('\0')不同,std::string_view不需要空终止符来标记字符串的结尾。因为它记录了字符串的长度
      2.从概念上讲,std::string_view只是字符串的视图,不能用于实际修改字符串。创建std::string_view无需拷贝数据。
      3.std::string_view可以使用许多不同类型的字符串进行初始化:C格式字符串、std::string、或另一个std::string_view。C风格字符串和std::string都会隐式转换为std::string_view。但std::string_view不会隐式转换为std::string:因为std::string会拷贝初始值(这是昂贵的),所以C++不允许将std::string_view隐式转换为std::string。这是为了防止意外地将std::string_view参数传递给std::string参数,以及无意中在可能不需要此类副本的情况下创建昂贵的副本。如果需要,可以有两个选择:
      (1).使用std::string_view初始值显式创建std::string;
      (2).使用static_cast将现有的std::string_view转换为std::string.

      以下为测试代码:注意注释说明

int test_string_view_functions()
{
	// unlike std::string, std::string_view has full support for constexpr
	constexpr std::string_view strv{ "china beijing" };

	// substr
	auto strv1 = strv.substr(6);
	std::cout << "strv1: " << strv1 << std::endl; // strv1: beijing
	//strv1[0] = 'B'; // 无论strv是不是constexpr, strv1都不能作修改

	char str1[]{ "beijing" };
	std::string_view strv2{ str1 };
	std::cout << "strv2: " << strv2 << std::endl; // strv2: beijing
	str1[0] = 'B';
	std::cout << "strv2: " << strv2 << std::endl; // strv2: Beijing

	std::cout << "at 2: " << strv2.at(2) << ", back: " << strv2.back() << "\n"; // at 2: i, back: g
	strv2.remove_prefix(3);
	std::cout << "remove_prefix 3: " << strv2 << "\n"; // remove_prefix 3: jing
	strv2.remove_suffix(2);
	std::cout << "remove_suffix 2: " << strv2 << "\n"; // remove_suffix 2: ji

	std::string str{};
	strv.copy(str.data(), strv.size()); // 注意str并非完整的std::string对象,str.size()为0
	std::cout << "str: " << str.data() << "\n"; // str: china beijing  note:是str.data()而不能是str

	// 注意以下两条语句的差异, str.size()为0
	std::cout << "strv.compare(str.data()): " << strv.compare(str.data()) << "\n"; // strv.compare(str.data()): 0
	std::cout << "strv.compare(str): " << strv.compare(str) << "\n"; // windows: strv.compare(str): 1  linux: strv.compare(str): 13

	auto found = strv.find(strv2);
	std::cout << "found: " << found << "\n"; // found: 9
	std::cout << "strv rfind: " << strv.rfind("i") << "\n"; // strv rfind: 10
	std::cout << "strv find_first_of: " << strv.find_first_of("i") << "\n"; // strv find_first_of: 2
	std::cout << "strv find_last_of: " << strv.find_last_of("i") << "\n"; // strv find_last_of: 10
	std::cout << "strv find_last_not_of: " << strv.find_last_not_of("in") << "\n"; // strv find_last_not_of: 12
	std::cout << "strv find_first_not_of: " << strv.find_first_not_of("in", 1) << "\n"; // strv find_first_not_of: 1

	// std::string_view不需要空终止符来标记字符串的结尾,因为它记录了字符串的长度
	char name[]{ 'c', 'h', 'i', 'n', 'a' };
	std::string_view strv3{ name, std::size(name) };
	std::cout << "strv3: " << strv3 << "\n"; // strv3: china
	std::cout << "name: " << name << "\n"; // windows: name: china烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫蘐?宋 linux: name: chinaBeijing

	// std::string_view to std::string: std::string_view不会隐式转换为std::string
	std::string str2{ strv }; // explicit conversion
	std::cout << "str2: " << str2 << "\n"; // str2: china beijing

	// std::string_view to C-style string: std::string_view -> std::string -> C-style string
	auto str3{ str2.c_str() };
	std::cout << "str3 length: " << strlen(str3) << "\n"; // str3 length: 13

	// std::string_view just only a view
	auto addr = [] {
		std::string str_csdn{ "https://blog.csdn.net/fengbingchun/" };
		std::string_view strv_csdn{ str_csdn };
		std::cout << "strv csdn: " << strv_csdn << "\n"; // strv csdn: https://blog.csdn.net/fengbingchun/
		return strv_csdn;
	};

	std::string_view strv4{ addr() };
	std::cout << "strv4 csdn: " << strv4 << "\n"; // windows: strv4 csdn: 葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺葺 linux: strv4 csdn: ▒(a▒▒\▒▒G▒cn.net/fengbingchun/

	// literals for std::string_view: 可以通过在双引号字符串文字后面使用sv后缀来创建类型为std::string_view的C风格字符串常量
	using namespace std::string_literals;      // access the s suffix
	using namespace std::string_view_literals; // access the sv suffix

	std::cout << "foo\n";   // no suffix is a C-style string literal
	std::cout << "goo\n"s;  // s suffix is a std::string literal
	std::cout << "moo\n"sv; // sv suffix is a std::string_view literal

	return 0;
}

      执行结果如下图所示:

      GitHub:https://github.com/fengbingchun/Messy_Test

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用python计算积分

先安装这个包 pip install scipy运行 import tkinter as tk from scipy.integrate import quad# 创建主窗口 root tk.Tk() root.title("积分计算器")# 定义计算积分的函数 def calculate_integral():# 获取用户输入的函数表达式function function_entry.get()# 获…

2023年最全的外贸建站新手教程

凡做外贸的&#xff0c;我相信在过去几年中通过亚马逊、速卖通等电商平台上都取得了一定的成功。然而&#xff0c;近年来电商平台上的竞争激烈&#xff0c;利润空间有限&#xff0c;流量获取困难和昂贵&#xff0c;这对许多外贸从业者造成了困扰。因此&#xff0c;为了减少对平…

分析概览 文章管理 草稿管理 图片管理 站点管理 主站 关于 登出 手写操作系统项目----进程

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家来访。 这里记录了&#xff0c;手写操作系统项目中关于进程的部分。 进程四要素 首先进程有四要素。 …

golang 八股文整理

目录 进程、线程、协程Go 的垃圾回收机制GC 的触发条件GC 的调优GMP 调度和 CSP 模型Goroutine 的调度原理Goroutine 的切换时机Context 结构原理Context 工作原理Context 使用场景Golang 的内存分配机制竞态问题内存逃逸golang 内存对齐机制golang 中 new 和 make 的区别&…

数二思维导图

高数上 第一章&#xff1a;函数、极限、连续 函数 函数的单调性、周期性、奇偶性复合函数 极限 求直接代入型的极限求∞∞型的极限用等价无穷小代换求00型的极限用洛必达法则求00型或∞∞型的极限求∞•0型的极限求幂指函数的极限函数的左右极限及需要求左右极限的情形极限的…

还不知道光场相机吗?

1.什么是光场&#xff1f; 光场&#xff08;light field&#xff09;&#xff1a;就是指光在每一个方向通过每一个点的光量。 从概念里&#xff0c;你至少可以得到两点信息&#xff1a; 光场包含光的方向光场包含一个点的光量 2.什么是光场相机 我们知道普通的相机拍照成像…

Parallels Client for Mac:改变您远程控制体验的革命性软件

在当今数字化的世界中&#xff0c;远程控制软件已经成为我们日常生活和工作中不可或缺的一部分。在众多远程控制软件中&#xff0c;Parallels Client for Mac以其独特的功能和出色的性能脱颖而出&#xff0c;让远程控制变得更加简单、高效和灵活。 Parallels Client for Mac是…

Redis的五种常用(基本)数据类型

目录 1、Redis简介 2、五种常用&#xff08;基本&#xff09;数据类型 2.1 String 数据结构 ⭐常用用法 举例&#xff08;Linux版本&#xff09; 2.2 List 数据结构 ⭐常用用法 举例&#xff08;Linux版本&#xff09; 2.3 Set 数据结构 ⭐常用用法 举例&#xf…

【未完待续】计算机组成与体系结构第三次试验:微程序控制器实验

计算机组成与体系结构第三次试验&#xff1a;微程序控制器实验 前言一、实验目的二、实验内容三、实验器件四、实验原理五、 实验步骤六、 实验结果七、思考题 前言 为了帮助同学们完成痛苦的实验课程设计&#xff0c;本作者将其作出的实验结果及代码贴至CSDN中&#xff0c;供…

机器学习中的核方法

一、说明 线性模型很棒&#xff0c;因为它们易于理解且易于优化。他们受苦是因为他们只能学习非常简单的决策边界。神经网络可以学习更复杂的决策边界&#xff0c;但失去了线性模型良好的凸性特性。 使线性模型表现出非线性的一种方法是转换输入。例如&#xff0c;通过添加特征…

BetaFlight飞控AOCODAF435V2MPU6500固件编译

BetaFlight飞控AOCODAF435V2MPU6500固件编译 1. 源由2. 准备2.1 板子2.2 代码2.3 工具 3. 配置修改4. 编译4.1 获取代码4.2 获取配置4.3 编译固件4.4 DFU烧录4.5 版本核对 5. 总结 1. 源由 刚拿到一块Aocoda F405V2 (MPU6500) AT32F435飞控板(替换主控芯片)。 Aocoda-RC F40…

unity中方向的两种表示:欧拉角和四元数

欧拉角&#xff1a;简单来说就是你可以选择 0度~360度 的范围 四元数&#xff1a;在计算机图像学中&#xff0c;四元数用于物体的旋转&#xff0c;是一种复杂&#xff0c;但效率较高的旋转方式 Quaternion结构体代表一个四元数&#xff0c;包含一个标量和一个三维向量&#x…

02、Python 字符串

目录 字符串的基础用法字符串包含引号字符串拼接获取用户输入长字符串原始字符串字节串字符串与字节串转换 字符串的基础用法 列字符串的内容几乎可以包含任何字符&#xff0c;英文字符也行&#xff0c;中文字符也行。 既可用单引号&#xff0c;也可用双引号 字符串包含引号…

函数和执行上下文

一.变量提升与函数提升 变量提升&#xff1a;通过var关键字定义&#xff08;声明&#xff09;的变量&#xff0c;在定义语句之前就可以访问到&#xff0c;只不过其值是undefined 函数提升&#xff1a;通过function声明的函数&#xff0c;在之前就可以调用&#xff0c;值是函数…

onehot-词嵌入-图嵌入

目录 一、为什么要有词嵌入&#xff1f; 二、one-hot编码&#xff1a; 三、什么是词嵌入&#xff08;word embedding&#xff09; 1、什么是嵌入矩阵&#xff1f; 2、为什么要设置维数&#xff1f; 3、相比one-hot编码的优点 4、什么是word2vec和GLove&#xff1f; 四、…

【计算机毕设案例推荐】高校学术研讨信息管理系统小程序SpringBoot+Vue+小程序

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 基于SpringBoot的高校学术研讨信息管理系统小程序 技术栈 SpringBoot小程序VueMySQLMaven 文…

珠宝行业软件,虽简约但不简单

作者&#xff1a;永远的新手 从学习猫框以来&#xff0c;一直向猫老师请教如何学习猫框和VFP的基础知识&#xff0c;猫老师不厌其烦传授知识于我。因为我是一位纯业余VFP爱好者&#xff0c;我的VFP几乎是零基础&#xff0c;接触猫框后&#xff0c;虽说时间很短&#xff0c;但其…

快来跟我一起抢先看看未来世界的出行,体验未来城市吧~

体验平台&#xff1a;Pony Robotaxi&#xff0c;Apollo Robotaxi&#xff0c;如棋Robotaxi 本文关键词Apollo&#xff0c;自动驾驶&#xff0c;智能出行&#xff0c;无人公交&#xff0c;无人清扫车等 感受未来世界的出行&#xff0c;体验未来城市&#xff01; 一、未来智能出行…

C++ vector 的模拟实现

目录 1. vector 类的成员变量 2. 无参构造 3. 析构函数 4. size_t capacity() 5. size_t size() 6. void reserve(size_t n) 7. 迭代器 8. void push_back(const T& x) 9. T& operator[](size_t pos) 10. iterator insert(iterator pos, const T& val…