What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:cpp:courses:cpp_basic_deep:chpt_7 [2024/12/09 07:36] – [配合模式使用] codingharecs:programming:cpp:courses:cpp_basic_deep:chpt_7 [2024/12/10 15:16] (当前版本) – [基于绑定的同步] codinghare
行 225: 行 225:
 ==配合模式使用== ==配合模式使用==
 <code cpp> <code cpp>
 +// 默认的模式是从起始位置开始替换
 +
 // 默认输出流中的内容是 test // 默认输出流中的内容是 test
 // 所有输出都会基于 test 输出 // 所有输出都会基于 test 输出
行 234: 行 236:
 std::cout << myObj3.str(); std::cout << myObj3.str();
 </code> </code>
 +==str() 的使用注意==
 +  * 返回 ''std::string''
 +  * 不要**间接**使用 ''str().c_str()'' 将字符串转换为 C 风格的字符串:该行为未定义
 +    * ''str()'' 返回的是右值
 +    * ''c_str()'' 指向了返回右值的内部的首地址,由于返回的是临时值,所以该访问未定义
 +==使用内存流进行拼接优化==
 +<code cpp>
 +// 类似 vector 的空间申请
 +// 可能每次都会进行 allocate
 +std::string s;
 +s += "hello";
 +s += "world";
 +s += "hello";
 +
 +// 改良
 +// 利用 ostringstream 的大缓存进行拼接
 +// 不会频繁的 allocate
 +std::ostringstream word;
 +word << "hello";
 +word << "world";
 +word << "hello";
 +
 +// 结果相同
 +std::cout << s;
 +std::cout << word.str();
 +</code>
 +====流的状态====
 +  * 提供额外的信息,使使用者针对状态进行对应的操作
 +  * 使用 ''std::io_base::iostate'' 维护状态
 +  * 非正常的状态的值都不是 ''0'',几种错误可以同时出现(通过 bit 之间的按位或, //BitMaskType//
 +===三种异常状态===
 +  * ''badbit'':不可恢复的流错误(比如读写未关联的流)
 +  * ''failbit'':可恢复的流错误:读 / 写类型不匹配且无法转换(格式化错误),双重关闭一个流
 +  * ''eofbit'':输入序列达到了文件尾部
 +==检测异常状态的方法==
 +[[https://en.cppreference.com/w/cpp/io/ios_base/iostate|bit 的组合与返回结果的关系]]
 +<code cpp>
 +// 使用 cin 的成员检测
 +std::cout << std::cin.good() 
 +          << std::cin.fail()
 +          << std::cin.bad()
 +          << std::cin.eof();
 +// 转换为 bool 值检测
 +          <<static_cast<bool>(std::cin) << std::endl;
 +</code>
 +  * ''fail'' 和 ''eof'' 可能会被同时设置,但意义不同
 +  * 转换为 bool 值时不会考虑 ''eof''
 +==利用状态==
 +<code cpp>
 +// 判断之前的输入提取是否成功
 +if(std::cin >> x) { //}
 +</code>
 +==复位流的状态==
 +  * ''clear()'' :设置当前流的指定状态(默认为 ''goodbit''
 +  * ''setstate()'':将某个状态**附加**到指定流上,
 +<code cpp>
 +std::cin.clear();
 +</code>
 +==捕获流的异常==
 +  * 可以通过 ''exception()'' 捕获流的异常
 +====流的定位====
 +提取写入时,需要考虑提取写入的位置(定位)。C++ 为此引入了流的定位:
 +  * 获取流
 +  * 设置流
 +===获取流位置===
 +  * ''tellg()'':获取输入流中,接下来要读取的字符的位置
 +  * ''tellp()'':获取输出流中,当前可以写入的位置(读的是 white space)
 +  * 两者返回一个为整数的 ''pos_type'' 类型。获取失败时,返回 ''pos_type(-1)''
 +    * ''fail() == true''
 +===设置流位置===
 +  * ''seekg()'' / ''seep()'':用于设置输入 / 输出流(覆盖输出)
 +==两个重载版本==
 +  * 设置绝对位置:接收 ''pos_type'' 的版本
 +  * 设置相对位置:接收基本位置(''beg'',''end'',''cur'')+ 位移
 +====流的同步====
 +系统默认的 “缓冲区满再输入到设备的” 行为很可能带来一些问题:
 +<code cpp>
 +// 如果 some test 所在流没有满,导致没有被输出到终端
 +std::cout << "some test";
 +std::string name;
 +// 导致输入时没有提示
 +std::cin >> name;
 +</code>
 +这种情况下需要**刷新缓冲区**,也就是强制输出缓冲区内容送到设备上。
 +===基于方法的同步===
 +  * ''flush()'':**输出**流同步,刷新缓冲区
 +<code cpp>
 +// 成员调用
 +std::cout.flush();
 +// 操纵符
 +std::cout << x << std::flush;
 +</code>
 +  * ''sync()'':**输入**流同步,实现由编译器定义
 +    * 同文件同时关联了输入输出流,要对输入流刷新,得到输出流的信息
 +    * 具体行为与编译器实现有关系
 +  * ''std::unitbuf''
 +    * 行为:大于一个字符的流必须被清除出缓存区
 +    * 结果:自动立即刷新(影响性能)
 +    * 通常与 ''std::cerr'' (标准错误输出)联用,因为错误信息必须及时更新
 +===基于绑定的同步===
 +C++ 中,任意流都可以绑定到一个**输出流**上。当绑定时,绑定流会记录被绑定流中的信息。当绑定时:
 +  * 绑定流在每次输入(输出)时,都会刷新**被绑定流**的缓冲区
 +  * 绑定流可以同时与多个输出流绑定
 +这种方法实际上从另外的角度解决了之前提到过的问题:
 +<code cpp>
 +// 如果 some test 所在流没有满,导致没有被输出到终端
 +std::cout << "some test";
 +std::string name;
 +// 导致输入时没有提示
 +std::cin >> name;
 +</code>
 +此时如果 ''std::cin'' 绑定了 ''std::cout'',那么当 ''std::cin'' 输入时,就会直接情况输出流的缓存,将我们需要的 //some test// 
 +文本输入终端。
 +===与 C 标准 I/O 的同步===
 +  * 缺省情况下会与 C 同步
 +  * 可以通过 ''sync_with_stdio'' 关闭同步