C++Primer5th 第十七章 标准库特殊设施



第十七章 标准库特殊设施

17.1 tuple类型

  • 定义在tuple头文件中
  • tuple是类似pair的模板
  • 一个tuple可以有任意数量的成员,每个确定的tuple类型的成员数目是固定的,但一个tuple类型的成员数目可以与另一个tuple类型不同.

17.1.1 定义和初始化tuple

当我们定义一个tuple时候,需要指出每个成员的类型

tuple <size_t, size_t, size_t> threeD;   //默认值初始化为0

tuple 的构造函数时explicit的,因此我们必须使用直接初始化语法

//生成tuple对象
auto i = make_tuple("string", 3, 2.3);
访问tuple的成员

不能像pair一样用first,second等,因为tuple类型的成员数目是没有限制的,使用 get 的标准库函数模板

传递给get一个tuple对象,返回指定成员的引用

//尖括号中的值必须是常量表达式,返回成员的引用, 0是第一个成员,1是第二个,依次类推
auto book = get<0>(i);
//返回成员数量
auto s = tuple_size<i>::value;
//使用成员的类型   这里面tuple_element<1, i>::type代表int类型
tuple_element<1, i>::type cnt = get<1>(i);
关系和相等运算符

只有两个tuple具有相等数量的成员时,才可以进行比较,两个成员使用==或<等运算符必须是合法的

17.1.2 使用tuple返回多个值

tuple常见的用途就是一个函数返回多个值



17.2 bitset类型

用于位运算,在头文件bitset中

17.2.1 定义和初始化bitset

bitset类是一个类模板,指定大小,大小需要时常量表达式

bitset<32> bitvec(1U);

bitset中的二进制位是未命名的,我们通过位置来访问他们,二进制位的位置是从0开始编号的,编号从0开始的二进制被称为低位,编号到最大值的二进制位称为高位

用unsigned值初始化bitset

当我们使用一个整型值来初始化bitset时,此值将被转换为unsigned long long类型并被当作位模式来处理,bitset中的二进制位是此模式的一个副本

  • 如果bitset大小大于一个unsigned long long , 则剩余高位置为0
  • 如果bitset大小小于一个unsigned long long , 则超出部分被丢弃
从一个string初始化bitset

可以从一个string或一个字符数组指针来初始化bitset

  • 字符串中下标最小的字符对应高位
  • 注意string下标标号从左往右递增,而bitset是从右往左递增

17.2.2 bitset操作

bit.size()是一个常量表达式,可以用在常量表达式的地方.

  • 我的理解:因为bitset指定大小的时候也需要传入一个常量表达式,因此在编译时候就知道了size,因此其也是个常量表达式
  • 下标运算符对const属性进行了重载
    • const版本的下标运算符在指定位 置位 时返回true,否则返回false
    • 非const版本返回bitset定义的一个特殊类型,允许操纵指定位的值
提取bitset的值

to_ulong和to_ullong操作返回一个值,保存了与bitset对象相同的位模式,只有bitset的大小小于ul和ull两种类型的大小的时候才能使用这个操作,否则会抛出异常

bitset的IO运算符

输入运算符从一个输入流读取字符,保存到临时的string对象中,直到读取字符数达到bitset大小或者是遇到不是1或0的字符,或是遇到文件尾或输入错误时候才停止, 之后用string对象来初始化bitset.

17.3 正则表达式

正则表达式是一种描述字符序列的方法,是一种极其强大的计算工具.

正则表达式库(RE库),定义在头文件regex中.

17.3.1 使用正则表达式库

看完整章,主要用在了字符串的匹配工作/格式化工作

指定regex对象的选项

regex r(re,f)//re是一个正则表达式,可以用string,迭代器等多种方式,f是一个标志

使用RE库的类型必须与输入序列的类型匹配

17.3.2 匹配与Regex迭代器类型

sregex_iterator
regex的迭代器是一种迭代器适配器,被绑定到一个输入序列和一个regex对象.

17.3.3 使用子表达式

正则表达式语法通常用括号表示子表达式

可单独访问每个子表达式,(序号),0表示整个表达式,1 表示第一个子表达式,一次类推

17.3.4 使用regex_replace

实现产找到给定的序列并替换为我们希望的另一个序列

可以设置控制配合和格式的标志

17.4 随机数

定义在头文件random中的随机数库通过一组协作的类来工作:

  • 随机数引擎类: 生成随机unsigned整数序列
  • 随机数分布类: 使用引擎返回服从特定概率分布的随机数

C++程序不应该使用rand(C库函数),而是使用default_random_engine类和恰当的分布类对象

17.4.1 随机数引擎和分布

标准库定义了多个随机数引擎类,区别是性能和随机性质量不同.
每个编译器会指定其中一个作为default_random_engine类型

随机数引擎的输出是不能够直接使用的,因为其范围通常与我们的需求不符

分布类型和引擎

分布类型定义了一个调用运算符,他接受一个随机数引擎作为参数,分布对象使用它的引擎参数生成随机数,并将其映射到指定分布.

我们所说的随机数发生器,其实指分布对象和引擎对象的组合

一个给定的随机数发生器一直会生成相同的随机数序列.一个函数如果定义了局部的随机数发生器,应该将其(包括引擎和分布对象)定义为static的.否则,每次调用函数都会生成相同的序列.

设置随机数发生器的种子

随机数发生器会生成相同的随机数序列这一特性在调试中很有用. 一旦我们的程序调试完毕,我们通常希望每次运行程序都会生成不同的随即结果.
可以通过提供一个 种子 来达到这个目的.

选取好的种子十分困呐,比较常用的方法是调用系统函数time,定义在ctime头文件中, time返回以秒计的时间,因此这种方式只适合生成种子的间隔位秒级或者更长的应用.

可以在初始化时候设置种子,也可以调用引擎的seed成员

17.4.2 其他随机数分布

生成随机实数

程序常需要一个随机浮点数的源,特别是经常需要0到1之间的随机数

新标库中,很容易获得随机浮点数,定义一个uniform_real_distribution类型对象

uniform_real_distribution<double> u(0,1);
使用分布的默认结果类型

每个分布模板都有一个默认模板实参,使用默认随机数类型是在模板名之后使用尖括号

uniform_real_distribution<> u(0,1); //使用默认double类型
生成非均匀分布的随机数

新标准库定义了20种分布类型.

  • 正态分布normal_distribution<>n(u,sigma);均值和标准差
bernoulli_distribution类是一个普通类,不是模板类
  • 此分布返回一个bool值,返回bool概率是一个常数,默认0.5
  • 由于引擎返回相同的随机数序列,通常应该在循环外声明和定义引擎对象和分布对象


17.5 IO库再探

17.5.1 格式化输入与输出

标准库定义了一组操纵符来修改流的格式状态,一个操纵符是一个函数或是一个对象,会影响流的状态,可以用作输入输出运算符的运算对象。

很多操纵符改变格式状态

操纵符用于两大类输出控制:控制数值的输出形式以及控制补白的数量和位置。大多数改变格式状态的操纵符都是设置/复原成对的。

当操纵符改变流格式的状态时,通常对之后的IO都生效,因此在不需要特殊格式的时候尽快恢复到默认状态。

控制布尔值的格式

使用boolalpha 使得false,true输出打印而不是0 和 1
取消使用noboolalpha

指定整型值的进制

hex, oct, dec 分别表示十六进制,八进制,十进制

在输出中指定进制

使用showbase显式进制 , noshowbase不显示

  • 前导0x十六进制
  • 前导0八进制
  • 无前导十进制

uppercase输出大写,nouppercase恢复

控制浮点数的格式
  • 多高精度打印浮点值,就是有多少个数字(默认六位数字精度打印)
  • 打印十六进制、定点十进制还是科学计数法形式 (标准库会选择可读性好的)
  • 对于没有小数部分的浮点值是否打印小数点 (默认不打印)

1.指定打印精度

默认情况控制打印数字的总数,按照舍入规则。

IO对象的成员precision和setprecision操纵符

setprecision操纵符和其他接收参数的操纵符定义在头文件iomanip中

cout.precision() 和 cout.precision(int) 是重载的,一个返回当前精度,一个设置指定的精度返回当前精度

2.指定浮点数记数法

除非需要控制浮点数表示形式,否则最好有标准库选择记数法

  • scientific使用科学计数法;
  • fixed定点十进制;
  • hexfloat是用十六进制格式;
  • defaultfloat恢复默认状态
  1. 打印小数点
    showpoint操纵符强制打印小数点

noshowpoint恢复默认格式

输出补白

按列打印时候要控制数据来良好展示

  • setw指定下一个数字或字符串值的最小空间,不改变输出流的内部状态,只决定下一个输出的大小.
  • left左对齐
  • right 右对齐 默认是右对齐
  • internal 左对齐符号,右对齐值,中间空间空格填满
  • setfill 使用一个默认字符代替空格补白
控制输入格式

默认情况,输入运算符会忽略空白符(空格\制表\换行\换纸\回车)

使用noskipws会令输入运算符读取空白符而不是跳过,skipws恢复默认行为

17.5.2 未格式化的输入/输出操作

标准库支持未格式化IO,允许我们将一个流当作一个无解释的字节序列来处理

单字节操作

is.get() is.get(ch)
os.put() 等可以每次一个字节地处理流

将字符放回输入流

有时候需要读取一个字符才能知道还未准备好处理它,希望将字符放回流中.有三种方法:

  • peek 返回输入流中下一个字符的副本, 不会将它从流中删除
  • unget 使得输入流向后移动,从而最后读取的值又回到流中
  • putback(ch) 退回从路中读取的最后一个值,需要参数,参数值是读取的最后一个值
从输入操作返回int值

peek和无参get() 都以int类型返回一个字符,因为这样可以返回文件尾标记EOF

多字节操作

一次处理大块数据

get和getline参数相同时行为类似,区别是处理分隔符的方式,get将分隔符留在iostream中作为下一个字符,getline读取并丢弃分隔符

确定读取了多少个字符

调用gcount来确定最后一个未格式化输入操作读取了多少个字符

17.5.3 流随机访问

stream和ostream不支持流随机访问, 以下内容只适用于fstream,sstream

各种流类型通常都支持对流中数据的随机访问,可以重定位流,使之跳过一些数据,首先读取最后一行,然后读取第一行.

标准库提供了seek定位和tell当前位置的函数对

seek和tell函数

g版本和p版本,g是读取数据,p是写入数据

只有一个标记

一个流中只有单一的标记,p和g都使用这一个标记,因此在读写操作切换时候必须进行seek操作重定位标记

重定位标记

seek两个版本,一个移动到绝对位置,另一个移动到偏移位置

访问标记

tellp和tellg返回一个pos_type值,表示流当前位置

读写同一个文件

注意每次更改标记以及返回标记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值