《C++标准程序库》笔记之三
本篇博客笔记顺序大体按照《C++标准程序库(第1版)》各章节顺序编排。
--------------------------------------------------------------------------------------------
11 Strings 字符串
本章单独列出,讲述C++标准程序库中的string(字符串)型别,包括针对基本template class basic_string<>及其标准特化型别string和wstring的详细内容。 C++标准程序库中的string class 使你可以将string当做一个一般型别而不会令用户感觉有任何问题。你可以像对待基本型别那样地复制、赋值和比较string,再也不必担心内存是否足够、占用的内存实际长度等问题,只需运用操作符操作函数即可。简而言之,C++标准程序库对于string的设计思维就是,让它的行为尽可能像基本型别,不会在操作上引起什么麻烦。
11.1
以下语句:
strring::size_type idx = filename.find('.');
(1)在字符串filename中搜寻第一个'.'字符。有好几个函数可以在字符串内实施搜寻功能,函数find()是其中之一。你也可以从后向前搜寻,或是搜寻子字符串,或是在字符串的某个范围内搜寻,或是同时搜寻数个字符。所有这些搜寻函数都返回第一个匹配位置(一个索引)。没错,返回值是个整数,而不是迭代器。字符串的一般接口并不依赖STL概念。然而字符串的确也提供了数种迭代器。所有搜寻函数的返回型别都是string::size_type,这是string class 定义的一个无正负号整数型别。当然啦,第一个字符的索引值为0,最后一个字符的索引值是numberOfCharacters-1.注意,numberOfCharacters并不是一个有效索引。和C-string不同,string对象的字符串尾部并没有一个特殊字符'\0'.
(2)如果搜寻失败,必须返回一个特殊值来表示,该值就是npos,定义于string class 中。如下面这一行语句用来检验搜寻动作是否失败: if (idx == string::npos) 注意,当你打算检验搜寻函数的返回值时,应该使用string::size_type型别而不是int或unsigned。否则上述与string::npos的比较动作将无法有效运行。
11.2
(1)string型别和wstring型别
C++标准程序库提供了两个basic_string<>特化版本:
1. string是针对char而预先定义的特化版本:
namespace std
{
typedef basic_string<char> string;
}
2. wstring 是针对wchar_t而预先定义的特化版本:
namespace std
{
typedef basic_string<wchar_t> wstring;
}
(2)操作函数(Operations)
表11.1 列出针对字符串而设计的所有操作函数

(3)string的构造函数和析构函数(Constructors and Destructors)

(4)Strings和C-Strings C++ Standard 将字符串字面常数的型别由char* 改为const char*。为了提供向下兼容性,C++ Standard规定了一个颇有争议的隐式转换,可从const char*隐式转换为char*。由于字符串字面常数的型别并非string,因此在新的string object和传统的C-strings之间必须存在一种强烈关系:在“strings和string-like object共通的操作场合”(例如比较、追加、插入等等动作)都应该可以使用C-strings(也即,对于string object提供支持的函数,也都应该相应的支持C-string)。或者具体地说,存在一个从const char* 到strings的隐式型别转换。然而却不存在一个从string object 到C-string的自动型别转换。这是出于安全考虑,防止意外转型导致奇异行为(char*经常有奇异的行为)和模棱两可(例如在一个结合了string和C-string的表达式中,既可以把string转化为char*,也可以反其道而行,这就导致模棱两可)。有好几种办法可以产生或改写/复制C-string。更明确地说,c_str()可以得到“string 对应的C-string”,所得结果和“以‘\0’为结尾的字符数组”一样。运用copy(),你也可以将字符串内容复制或写入既有的C-string或字符数组内。
请注意:
1. ‘\0’ 在string之中并不具有特殊意义,但在一般C-string中却用来标识字符串结束。在string中,字符‘\0’和其它字符的地位完全相同。
2. 千万不要以null指标(NULL)取代char*作为参数,这样会导致奇异行为,因为NULL具有整数型别,在单整数型别的重载函数版本上会被解释为数字0或“其值为0”的字符。
有三个函数可以将字符串内容转换为字符数组或C-string:
1. data() 以字符数组的形式返回字符串内容。由于并未追加‘\0’字符,所以返回型别并非有效的C-string。
2. c_str() 以C-string形式返回字符串内容,也就是在尾端添加‘\0’字符。
3. copy() 将字符串内容复制到“调用者提供的字符数组”中。不添加‘\0’字符。
std::string s("");
atoi(s.c_str());
f(s.data(), s.length());
char buffer();
s.copy(buffer, );
s.copy(buffer, , );
注意,data() 和 c_str() 返回的字符数组由该字符串拥有。也就是说调用者千万不可修改它或释放其内存。例如:
std::string s;
...
foo(s.c_str()); // s.c_str() is valid during the whole statement const char* p;
p = s.c_str(); // p refers to the contents of s as a C-string p
foo(p); // OK(p is still valid)
s += "ext"; // invalidates p
foo(p); // ERROR:argument p is not valid
一般而言,整个程序中你应该坚持使用strings,直到你必须将其内容转化为char*时才把它们转换为C-string。请注意c_str()和data()的返回值有效期限在下一次调用non-const成员函数时即告终止。
让string拥有足够的容量是很重要的,原因有二:
1. 重新分配会造成所有指向string的references、pointers和iterators失效。
2. 重新分配很耗时间。
容量概念应用于string和应用于vector是相同的;但有一个显著差异:面对string你可以调用reserve()来缩减实际容量,而vector的reserve()却没有这项功能。string的reserve()是一种非强制性适度缩减请求——不保证一定可以如愿。C++ Standard 规定,唯有在响应reserve() 调用时,容量才有可能缩减。因此即使发生“字符被删除或被改变”的事情,任何其他字符只要位于“被操作字符”之前,指向它们身上的那些references、pointers和iterators就仍然保持有效。
(5)元素存取(Element Access)
String有两种方法可以访问单一字符:subscript(下标)操作符[] 和 成员函数 at()。但有两点区别:
1. operator [] 并不检查索引是否有效,at() 则会检查。如果at()指定的索引无效,系统会抛出out_of_range异常。如果调用operator[]指定的索引无效,其行为未有定义——可能存取非法内存,引起边缘效应或崩溃。
2. 对于 operator[] 的const 版本,最后一个字符的后面位置也是有效的。此时的实际字符数是有效索引。在此情况下 operator[] 的返回值是“由char型别值default构造函数所产生”的字符。因此,对于型别为string的对象,返回值为“\0”字符。
其他任何情况(包括成员函数at() 和 operator[] 的non-const 版本),实际字符数都是个无效索引。如果使用该索引,会引发异常,或导致未定义行为。下例:
const std::string cs("nico"); // cs contains: 'n' 'i' 'c' 'o'
std::string s("abcde"); // s contains: 'a' 'b' 'c' 'd' 'e'
s[] // yields 'c'
s.at() // yields 'c'
s[] // ERROR:undifined behavior
s.at() // throws out_of_range
s.[s.length()] // ERROR:undefined behavior
cs[cs.length()] // yields '\0'
s.at(s.length()) // throw out_of_range
cs.at(cs.length()) // throw out_of_range
为了允许更改string内容,operator[] 的 non-const 版本和at() 都返回字符的reference。一旦发生重分配行为,那些reference立即失效:
std::string s("abcde"); // s contains: 'a' 'b' 'c' 'd' 'e'
char& r = s[]; // reference to third character
char* p = &s[]; // pointer to fourth character
r = 'X'; // OK, s contains: 'a' 'b' 'X' 'd' 'e'
*p = 'Y'; // OK, s contains: 'a' 'b' 'X' 'Y' 'e'
s = "new long value"; // realloction invalidates r and p
r = 'X'; // ERROR: undefined behavior
*p = 'Y'; // ERROR: undefined behavior
(6)I/O操作符 ">>", "<<"
String classes 在命名空间std内还提供了一种用于逐行读取的特殊函数:std::getline() 。该函数读取所有字符,包括开头的空格符,直到遭遇分行符号或end_of_file。分行符号可指定,不可添加。缺省情况下分行符号为newline字符。
(7)表11.5 列出来了Strings搜寻函数。

注意,所有搜寻函数都返回符合搜寻条件之字符区间内的第一个字符的索引。如果搜寻不成功,则返回npos,其类型为 std::string::size_type。 不能以 int 或 unsigned 作为返回值型别;否则返回值与string::npos之间的比较可能无法正确执行。这是因为npos在basic_string类模板里面被设计为-1。不幸的是size_type(由字符串配置器allocator定义)需为无正负号整数型别。因为缺省配置器以型别size_t作为size_type。于是 -1 被转换为无正负号整数型别,npos也就成了该型别的最大无符号值。
(8)Strings对迭代器的支持
1. string是字符的有序群集,所以C++标准程序库为strings提供了相应接口,以便将字符串当做STL容器使用。
2. String迭代器是random access(随机存取)迭代器。
3. 对迭代器而言,如果发生重分配(reallocation),或其所指值发生某些变化,迭代器就会失效。
表11.6 提供了一份迭代器操作函数列表

(9)Strings 和 Vectors
两者都是一种动态数组。因此可以把strings视为一种“以字符作为元素”的特定vectors。实用上可把string当作STL容器使用。当两者的主要差异在于各有目标:
1. vectors 首要目标是处理和操作容器内的元素,而非容器整体。因此实作时通常会为“容器元素的操作行为”进行优化。
2. strings 主要是把整个容器视为整体,进行处理和操作,因此实作时通常会为“整个容器的赋值和传递”进行优化。
不同的目标导致完全不同的实作手法。例如strings 通常采用reference counting(这种手法可以加速string的复制和赋值)手法,vectors则决不会如此。
《C++标准程序库》笔记之三的更多相关文章
- C++标准程序库笔记之一
本篇博客笔记顺序大体按照<C++标准程序库(第1版)>各章节顺序编排. ---------------------------------------------------------- ...
- 《C#图解教程》读书笔记之三:方法
本篇已收录至<C#图解教程>读书笔记目录贴,点击访问该目录可获取更多内容. 一.方法那些事儿 (1)方法的结构:方法头—指定方法的特征,方法体—可执行代码的语句序列: (2)方法的调用:参 ...
- sc7731 Android 5.1 LCD驱动简明笔记之三
此篇笔记基于sc7731 - android 5.1,对lcd的gralloc库做一个简明笔记. 第一部分 调用gralloc.sc8830.so所谓的Gralloc模块,它就是一个模块,一个操作ke ...
- Django 学习笔记之三 数据库输入数据
假设建立了django_blog项目,建立blog的app ,在models.py里面增加了Blog类,同步数据库,并且建立了对应的表.具体的参照Django 学习笔记之二的相关命令. 那么这篇主要介 ...
- 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析
刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...
- 【Visual C++】游戏编程学习笔记之三:游戏循环的使用
本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44208419 作者:Zee ...
- Kinect开发笔记之三Kinect开发环境配置具体解释
0.前言: 首先说一下我的开发环境,Visual Studio是2013的,系统是win8的64位版本号,SDK是Kinect for windows SDK 1.8版本 ...
- 学习笔记之三十年软件开发之路 - Things I Learnt The Hard Way (in 30 Years of Software Development)
三十年软件开发之路 https://mp.weixin.qq.com/s/EgN-9bIHonRid1DM0csQDw https://blog.juliobiason.net/thoughts/th ...
- Vue.js 学习笔记之三:与服务器的数据交互
显而易见的,之前的02_toDoList存在着一个很致命的缺陷.那就是它的数据只存在于浏览器端,一但用户关闭或重新载入页面,他之前加入到程序中的数据就会全部丢失,一切又恢复到程序的初始状态.要想解决这 ...
随机推荐
- elasticsearch系列六:聚合分析(聚合分析简介、指标聚合、桶聚合)
一.聚合分析简介 1. ES聚合分析是什么? 聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值.最小值,计算和.平均值等.ES作为 ...
- css3 -- 自动生成序号(不使用JS,可任意排序)
需求:一个table 需要在第一列生成序号:1.2.3.4.5...... 并且自适应行数 不使用后台程序,开始考虑使用JS,但是一旦前台排序后,序号就乱了,最后采用CSS的一个计数器方法实现! & ...
- OpenStack配置解析库oslo.config的使用方法
OpenStack的oslo项目旨在独立出系统中可重用的基础功能,oslo.config就是其中一个被广泛使用的库,该项工作的主要目的就是解析OpenStack中命令行(CLI)或配置文件(.conf ...
- winform 应用log4net做日志记录到mysql
1.nuget装log4net 2.nuget控件台装 mysql.data Install-Package mysql.data -version 6.8.3 (太高的版本用不了,切记) 3.修改a ...
- 7款HTML5精美应用教程 让你立即爱上HTML5
你喜欢HTML5吗?我想下面的这7个HTML5应用一定会让你爱上HTML5的,不信就一起来看看吧. 1.HTML5/jQuery雷达动画图表 图表配置十分简单 之前我们介绍过不少形形色色的HTML5图 ...
- 轻松利用WayOs修正版配合推广EasyRadius用户微信公众自助平台
各大平台争相推出微信公共平台服务,EasyRadius也不会OUT!!! EasyRadius已推出微信公共平台自助服务,用户只需要把公众平台设置为开发者模式,并设置专用的地址,就可以实现旗下宽带用户 ...
- jquery获取data-xxx自定义属性的值遇到的问题
直接用jquery的 data("name") 获取 data-name的值有问题,获取的只是最初的值,即使后边改变也不会变,所以还是要用attr("data-name& ...
- 前端常用linux命令
文件和目录 cd /home 进入 '/ home' 目录' cd .. 返回上一级目录 cd ../.. 返回上两级目录 cd 进入个人的主目录 cd ~user1 进入个人的主目录 cd - 返回 ...
- redis的其他命令
1.del del key-name 用于删除已存在的键.不存在的 key 会被忽略 返回值:被删除 key 的数量 2.DUMP DUMP key-name 用于序列化给定 key ,并返回被序列化 ...
- Android开发学习笔记-SharedPreferences的用法
SharedPreferences介绍: 做软件开发应该都知道,很多软件会有配置文件,里面存放这程序运行当中的各个属性值,由于其配置信息并不多,如果采用数据库来存放并不划算,因为数据库连接跟操作等 ...