- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
F.2 数据信息、构造函数及其他
可以根据其效果来描述构造函数。由于类的私有部分可能依赖于实现,因此可根据公用接口中可用的数据来描述这些效果。表 F.1 列出了一些方法,它们的返回值可用来描述构造函数和其他方法的效果。注意,其中的大部分术语来自 STL。
表 F.1 一些 string 数据方法
方 法 | 返 回 值 |
---|---|
begin( ) | 指向字符串第一个字符的迭代器 |
cbegin( ) | 一个 const_iterator,指向字符串中的第一个字符(C++11) |
end( ) | 为超尾值的迭代器 |
cend( ) | 为超尾值的 const_iterator(C++11) |
rbegin( ) | 为超尾值的反转迭代器 |
crbegin( ) | 为超尾值的反转 const_iterator(C++11) |
rend( ) | 指向第一个字符的反转迭代器 |
crend( ) | 指向第一个字符的反转 const_iterator(C++11) |
size( ) | 字符串中的元素数,等于 begin( ) 到 end( ) 之间的距离 |
length( ) | 与 size( ) 相同 |
capacity( ) | 给字符串分配的元素数。这可能大于实际的字符数,capacity( ) – size( ) 的值表示在字符串末尾附加多少字符后需要分配更多的内存 |
max_size( ) | 字符串的最大长度 |
data( ) | 一个指向数组第一个元素的 const charT指针,其第一个 size( ) 元素等于this 控制的字符串中对应的元素,其下一个元素为 charT 类型的 charT(0) 字符(字符串末尾标记)。当 string 对象本身被修改后,该指针可能无效 |
c_str( ) | 一个指向数组第一个元素的 const charT指针,其第一个 size( ) 元素等于this 控制的字符串中对应的元素,其下一个元素是 charT 类型的 charT(0)字符(字符串尾标识)。当 string 对象本身被修改后,该指针可能无效 |
get_allocator( ) | 用于为字符串 object 分配内存的 allocator 对象的副本 |
请注意 begin( )、rend( )、data( ) 和 c_str( ) 之间的差别。它们都与字符串的第一个字符相关,但相关的方式不同。begin( ) 和 rend( ) 方法返回一个迭代器,正如第 16 章讨论的,这是一种广义指针。具体地说,begin( ) 返回一个正向迭代器模型,而 rend( ) 返回反转迭代器的一个副本。这两种方法都引用了 string 对象管理的字符串(由于 string 类使用动态内存分配,因此实际的 string 内容不一定位于对象中,因此,我们使用术语“管理”来描述对象和字符串之间的关系)。可以将返回迭代器的方法用于基于迭代器的 STL 算法中。例如,可以使用 STL reverse( ) 函数来反转字符串的内容:
而 data( ) 和 c_str( ) 方法返回常规指针。另外,返回的指针将指向存储字符串字符的数组的第一个元素。该数组可能(但不一定)是 string 对象管理的字符串的副本(string 对象采用的内部表示可以是数组,但不一定非得是数组)。由于返回的指针可能指向原始数据,而原始数据是 const,因此不能用它们来修改数据。另外,当字符串被修改后,将不能保证这些指针是有效的,这表明它们可能指向原始数据。data( ) 和 c_str( ) 的区别在于,c_str( ) 指向的数组以空值字符(或与之等价的其他字符)结束,而 data( ) 只是确保实际的字符串字符是存在的。因此,c_str( ) 方法期望接受一个 C-风格字符串参数:
同样,data( ) 和 size( ) 可用作这种函数的参数,即接受指向数组元素的指针和表示要处理的元素数目的值:
C++实现可能将 string 对象的字符串表示为动态分配的 C-风格字符串,并使用 char*指针来实现正向迭代器。在这种情况下,实现可能让 begin( )、data( ) 和 c_str( ) 都返回同样的指针,但返回指向 3 个不同的数据对象的引用也是合法的(虽然更复杂)。
在 C++11 中,模板类 basic_string 有 11 个构造函数(在 C++98 中只有 6 个)和一个析构函数:
有些新增的构造函数以不同的方式处理参数。例如,C++98 包含如下复制构造函数:
而 C++11 用三个构造函数取代了它—上述列表中的第 2~4 个,这提高了编码效率。真正新增的只有移动构造函数(使用右值引用的构造函数,这在第 18 章讨论过)以及使用 initializer_list 参数的构造函数。
注意到大多数构造函数构造函数都有一个下面这样的参数:
Allocator 是用于管理内存的 allocator 类的模板参数名;Allocator( ) 是这个类的默认构造函数。因此,在默认情况下,构造函数将使用 allocator 对象的默认版本,但它们使得能够选择使用 allocator 对象的其他版本。下面分别介绍这些构造函数。
F.2.1 默认构造函数
默认构造函数的原型如下:
通常,接受 allocator 类的默认参数,并使用该构造函数来创建空字符串:
调用该默认构造函数后,将存在下面的关系:
- data( ) 方法返回一个非空指针,可以将该指针加上 0;
- size( ) 方法返回 0;
- capacity( ) 的返回值不确定。
将 data( ) 返回的值赋给指针 str 后,第一个条件意味着 str + 0 是有效的。
F.2.2 使用 C-风格字符串的构造函数
使用 C-风格字符串的构造函数让您能够将 string 对象初始化为一个 C-风格字符串;从更普遍的意义上看,它使得能够将 charT 具体化初始化为一个 charT 数组:
为确定要复制的字符数,该构造函数将 traits::length( ) 方法用于 s 指向的数组(s 不能为空指针)。例如,下面的语句使用指定的字符串来初始化 toast 对象:
char 类型的 traits::length( ) 方法将使用空值字符来确定要复制多少个字符。
该构造函数被调用后,将存在下面的关系:
- data( ) 方法返回一个指针,该指针指向数组 s 的一个副本的第一个元素;
- size( ) 方法返回的值等于 trains::length( ) 的值;
- capacity( ) 方法返回一个至少等于 size( ) 的值。
F.2.3 使用部分 C-风格字符串的构造函数
使用部分 C-风格字符串的构造函数让您能够使用 C-风格字符串的一部分来初始化 string 对象;从更广泛的意义上说,该构造函数使得能够使用 charT 数组的一部分来初始化 charT 具体化:
该构造函数将 s 指向的数组中的 n 个字符复制到构造的对象中。请注意,如果 s 包含的字符数少于 n,则复制过程将不会停止。如果 n 大于 s 的长度,该构造函数将把字符串后面的内存内容解释为 charT 类型的数据。
该构造函数要求 s 不能是空值指针,同时 n<npos(npos 是一个静态类常量,它是字符串可能包含的最大元素数目)。如果 n 等于 npos,该构造函数将引发一个 out_of_range 异常(由于 n 的类型为 size_type,而 npos 是 size_type 的最大值,因此 n 不能大于 npos);否则,在该构造函数被调用后,将存在下面的关系:
- data( ) 方法返回一个指针,该指针指向数组 s 的副本的第一个元素;
- size( ) 方法返回 n;
- capacity( ) 方法返回一个至少等于 size( ) 的值。
F.2.4 使用左值引用的构造函数
复制构造函数类似于下面这样:
它使用一个 string 参数初始化一个新的 string 对象:
其中,ida 将是 mel 管理的字符串副本。
下一个构造函数要求您指定一个分配器:
调用这两个构造函数中的任何一个后,将存在如下关系:
- data( ) 方法返回一个指针,该指针指向分配的数组副本,该数组的第一个元素是 str.data( ) 指向的;
- size( ) 方法返回 str.size() 的值;
- capacity( ) 方法返回一个至少等于 size( ) 的值。
再下一个构造函数让您能够指定多项内容:
第二个参数(pos)指定了源字符串中的位置,将从这个位置开始进行复制:
位置编号从 0 开始,因此,位置 4 是字符 p。所以,et 被初始化为“phone home”。
第 3 个参数 n 是可选的,它指定要复制的最大字符数目,因此下面的语句将 pt 初始化为字符串“phone”:
然而,该构造函数不能跨越源字符串的结尾,例如,下面的语句将在复制句点后停止:
因此,该构造函数实际复制的字符数量等于 n 和 str.size( )-pos 中较小的一个。
该构造函数要求 pos 不大于 str.size( ),也就是说,被复制的初始位置必须位于源字符串中。如果情况并非如此,该构造函数将引发 out_of_range 异常;否则,该构造函数被调用后,copy_len 将是 n 和 str.size( )-pos 中较小的一个,并存在下面的关系:
- data( ) 方法返回一个指向字符串的指针,该字符串包含 copy_len 个元素,这些元素是从 str 的 pos 位置开始复制而得到的;
- size( ) 方法返回 copy_len;
- capacity( ) 方法返回一个不小于 size( ) 的值。
F.2.5 使用右值引用的构造函数(C++11)
C++11 给 string 类添加了移动语义。正如第 18 章介绍的,这意味着添加一个移动构造函数,它使用右值引用而不是左值引用:
在实参为临时对象时将调用这个构造函数:
正如第 18 章讨论的,three 将获取 operator + () 创建的对象的所有权,而不是将该对象复制给 three,再销毁原始对象。
第二个使用右值引用的构造函数让您能够指定分配器:
调用这两个构造函数中的任何一个后,将存在如下关系:
- data( ) 方法返回一个指针,该指针指向分配的数组副本,该数组的第一个元素是 str.data( ) 指向的;
- size( ) 方法返回 str.size() 的值;
- capacity( ) 方法返回一个至少等于 size( ) 的值。
F.2.6 使用一个字符的 n 个副本的构造函数
使用一个字符的 n 个副本的构造函数创建一个由 n 个 c 组成的 string 对象:
该构造函数要求 n<npos。如果 n 等于 npos,该构造函数将引发 out_of_range 异常;否则,该构造函数被调用后,将存在下面的关系:
- data( ) 方法返回一个指向字符串第一个元素的指针,该字符串由 n 个元素组成,其中每个元素的值都为 c;
- size( ) 方法返回 n;
- capacity( ) 方法返回不小于 size( ) 的值。
F.2.7 使用区间的构造函数
使用区间的构造函数使用一个用迭代器定义的、STL-风格的区间:
begin 迭代器指向源字符串中要复制的第一个元素,end 指向要复制的最后一个元素的后面。
这种构造函数可用于数组、字符串或 STL 容器:
在第一种用法中,InputIterator 的类型为 const char *;在第二种用法中,InputIterator 的类型为 vector<char>::iterator。
调用该构造函数后,将存在下面的关系:
- data( ) 方法返回一个指向字符串的第一个元素的指针,该字符串是通过复制区间[begin,end)中的元素得到的;
- size( ) 方法返回 begin 到 end 之间的距离(度量距离时,使用的单位为对迭代器解除引用得到的数据类型的长度);
- capacity( ) 方法返回一个不小于 size( ) 的值。
F.2.8 使用初始化列表的构造函数(C++11)
这个构造函数接受一个 initializer_list<charT>参数:
可将一个用大括号括起的字符列表作为参数:
这并非初始化 string 的最方便方式,但让 string 的接口类似于 STL 容器类。
initializer_list 类包含成员函数 begin( ) 和 end( ),调用该构造函数的影响与调用使用区间的构造函数相同:
F.2.9 内存杂记
有些方法用于处理内存,如清除内存的内容、调整字符串长度或容量。表 F.2 列出了一些与内存相关的方法。
表 F.2 一些与内存有关的方法
方 法 | 作 用 |
---|---|
void resize(size_type n) | 如果 n>npos,将引发 out_of_range 异常;否则,将字符串的长度改为 n,如果 n<size( ),则截短字符串,如果 n>size( ),则使用 charT(0) 中的字符填充字符串 |
void resize(size_type n, charT c) | 如果 n>npos,将引发 out_of_range 异常;否则,将字符串长度改为 n,如果 n<size( ),则截短字符串,如果 n>size( ),则使用字符 c 填充字符串 |
void reserve(size_type res_arg = 0) | 将 capacity( ) 设置为大于或等于 res_arg。由于这将重新分配字符串,因此以前的引用、迭代器和指针将无效 |
void shrink_to_fit( ) | 请求让 capacity( ) 的值与 size( ) 相同,这是 C++11 新增的 |
void clear( ) noexcept | 删除字符串中所有的字符 |
bool empty( )const noexcept | 如果 size( )==0,则返回 true |
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论