C++流缓冲区与国际化编程全解析
立即解锁
发布时间: 2025-08-22 00:43:54 阅读量: 17 订阅数: 23 


深入解析C++标准库:从入门到精通
### C++ 流缓冲区与国际化编程全解析
#### 1. 流缓冲区使用示例
以下是一个使用流缓冲区的示例代码:
```cpp
// io/inbuf1.cpp
#include <iostream>
#include "inbuf1.hpp"
int main()
{
inbuf ib;
// create special stream buffer
std::istream in(&ib);
// initialize input stream with that buffer
char c;
for (int i = 1; i <= 20; i++) {
// read next character (out of the buffer)
in.get(c);
// print that character (and flush)
std::cout << c << std::flush;
// after eight characters, put two characters back into the stream
if (i == 8) {
in.unget();
in.unget();
}
}
std::cout << std::endl;
}
```
该程序在循环中读取字符并输出。当读取到第 8 个字符后,会将两个字符放回流中,因此第 7 和第 8 个字符会被打印两次。
#### 2. 性能问题
在 I/O 操作对性能至关重要的应用中,虽然流类通常效率较高,但仍有进一步优化的空间。
##### 2.1 与 C 标准流的同步
默认情况下,8 个 C++ 标准流(4 个窄字符流 `cin`、`cout`、`cerr` 和 `clog` 及其宽字符对应流)与 C 标准库中的相应文件同步。这种同步可能会带来不必要的开销,例如使用标准 C 文件实现标准 C++ 流会抑制相应流缓冲区的缓冲功能。
为了切换到更好的实现方式,`ios_base` 类定义了静态成员函数 `sync_with_stdio()`,其相关信息如下表所示:
| 静态函数 | 含义 |
| --- | --- |
| `sync_with_stdio()` | 返回标准流对象是否与标准 C 流同步以及是否支持并发 |
| `sync_with_stdio(false)` | 禁用 C++ 和 C 流的同步(必须在任何 I/O 操作之前调用) |
要禁用同步,可使用以下代码:
```cpp
std::ios::sync_with_stdio(false);
// disable synchronization
```
需要注意的是,必须在进行任何其他 I/O 操作之前禁用同步,否则会导致实现定义的行为。该函数返回上一次调用时传入的值,如果之前未调用过,则返回 `true`,以反映标准流的默认设置。自 C++11 起,禁用与标准 C 流的同步也会禁用并发支持。
##### 2.2 流缓冲区的缓冲
缓冲 I/O 对于提高效率非常重要。一方面,系统调用通常比较昂贵,应尽量避免;另一方面,在 C++ 中,格式化 I/O 函数使用流缓冲区迭代器访问流,操作流缓冲区迭代器比操作指针慢。
然而,有三个方面会影响有效缓冲:
1. **实现简单性**:无缓冲地实现流缓冲区通常更简单。如果相应的流不经常使用或仅用于输出,缓冲可能不是那么重要。但对于频繁使用的流缓冲区,应实现缓冲。
2. **刷新标志**:`unitbuf` 标志会使输出流在每次输出操作后刷新,`flush` 和 `endl` 操纵符也会刷新流。为了获得最佳性能,应尽量避免使用这三个。但在向控制台写入时,在写入完整行后刷新流可能仍然是合理的。如果程序大量使用 `unitbuf`、`flush` 或 `endl`,可以考虑使用特殊的流缓冲区。
3. **流绑定**:使用 `tie()` 函数绑定流会导致额外的刷新操作,因此只有在确实必要时才应绑定流。
在实现新的流缓冲区时,可以先不实现缓冲,若发现该流缓冲区成为性能瓶颈,再实现缓冲,而不会影响应用程序的其他部分。
##### 2.3 直接使用流缓冲区
`basic_istream` 和 `basic_ostream` 类中读写字符的成员函数遵循相同的模式:首先构造一个相应的哨兵对象,然后执行操作。对于无格式 I/O,大多数操作通常是无用的,只有在多线程环境中使用流时,锁定操作可能有用。因此,在进行无格式 I/O 时,直接使用流缓冲区可能更好。
可以使用 `<<` 和 `>>` 运算符与流缓冲区进行交互:
- **输出设备输入**:通过将流缓冲区的指针传递给 `<<` 运算符,可以输出其设备的所有输入,这可能是使用 C++ I/O 流复制文件的最快方法。示例代码如下:
```cpp
// io/copy1.cpp
#include <iostream>
int main ()
{
// copy all standard input to standard output
std::cout << std::cin.rdbuf();
}
```
- **直接读取到流缓冲区**:通过将流缓冲区的指针传递给 `>>` 运算符,可以直接将数据读取到流缓冲区。示例代码如下:
```cpp
// io/copy2.cpp
#include <iostream>
int main ()
{
// copy all standard input to standard output
std::cin >> std::noskipws >> std::cout.rdbuf();
}
```
需要注意的是,必须清除 `skipws` 标志,否则会跳过输入的前导空白字符。
即使对于格式化 I/O,直接使用流缓冲区也可能是合理的。例如,在循环中读取多个数值时,只需构造一个在整个循环执行期间都存在的哨兵对象,然后在循环中手动跳过空白字符,使用 `num_get` 方面直接读取数值。
需要注意的是,流缓冲区本身没有错误状态,也不知道连接到它的输入或输出流。因此,调用 `out << in.rdbuf();` 不会因失败或文件结束而改变 `in` 的错误状态。
#### 3. 国际化
随着全球市场的重要性日益增加,软件开发中的国际化(i18n)也变得越来越重要。C++ 标准库提供了编写国际化程序的概念,主要影响 I/O 和字符串处理。
##### 3.1 国际化的重要方面
国际化涉及两个重要方面:
1. **字符集特性**:不同的字符集具有不同的特性,对于字符集超过 256 个字符的情况,`char` 类型不足以表示字符,需要灵活的解决方案。
2. **本地约定**:程序用户期望看到遵循本国或文化约定的内容,如日期、货币值、数字和布尔值的格式。
C++ 标准库使用 `locale` 对象来表示可扩展的方面集合,以适应特定的本地约定。大多数国际化机制对程序员来说只需要进行最少的额外工作,例如在使用 C++ 流机制进行 I/O 时,数值会根据某个 `locale` 的规则进行格式化,程序员只需指示 I/O 流类使用用户的偏好。此外,程序员还可以直接使用 `locale` 对象进行格式化、排序、字符分类等操作。
##### 3.2 C++11 中的新特性
C++11 为本地化库添加了许多重要特性:
- 对于 `locale` 和 `facet`,现在可以传递 `
0
0
复制全文
相关推荐









