第十章---关闭同步流及注意事项及详细分析cin.ignore;

1.关闭同步流及注意事项

1.关闭同步流:ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

ios::sync_with_stdio(0);

这条语句的目的是告诉C++的IO库,不要将C++的iostream对象(如cin, cout, cerr等)与C的stdio库(如stdin, stdout, stderr等)同步。这通常用于提高输入输出的效率,特别是在需要大量IO操作时。

  • ios::sync_with_stdiostd::ios_base 类的一个枚举值成员,用于控制iostream库是否与C的stdio库同步。
  • 参数 0 表示不进行同步(即禁用同步),而 1 表示启用同步(这是默认行为)。
    禁用同步可以减少iostream操作时的开销,因为iostream不再需要等待stdio操作完成。
cin.tie(0);

这条语句用于解除cin与cout之间的绑定。默认情况下,cin和cout是绑定的,这意味着每次进行cin操作后,都会自动刷新cout缓冲区。

  • cin.tie() 是一个成员函数,返回当前与cin绑定的ostream对象,默认是cout。
  • 参数 0 表示解除绑定,因此cin操作后不会自动刷新cout缓冲区。
    解除绑定可以减少不必要的缓冲区刷新,从而提高性能。
cout.tie(0);

这条语句与 cin.tie(0); 类似,但它是用于解除cout与其他iostream对象的绑定。

  • cout.tie() 是一个成员函数,返回当前与cout绑定的istream对象,默认是cin。
  • 参数 0 表示解除绑定。
    虽然通常情况下,我们主要关注的是解除cin和cout之间的绑定,但在某些情况下,也可能需要解除cout与其他iostream对象的绑定。
另一种方法:
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
  • ios::sync_with_stdio(false); 关闭了C++ IO流与C的stdio库的同步,提高了性能。
  • cin.tie(NULL); 解除了cin和cout之间的绑定,这样cin的操作不会导致cout自动flush。
  • cout.tie(NULL); 通常这一行是不必要的,因为前面已经通过 cin.tie(NULL) 解除了绑定,但是它显式地指出了cout不再与任何流绑定。
区别

首先这两种关闭同步流的代码在功能上并没有区别但是,ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); 中的 cin.tie(0)cout.tie(0) 是不正确的用法,应该使用 cin.tie(NULL)cout.tie(NULL) 来解除流之间的绑定。
正确的代码:

ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);

ios::sync_with_stdio(0)ios::sync_with_stdio(false) 实际上是相同的,0 在这里只是表示逻辑上的假值,关闭同步。使用 false 可能更具可读性,但它们的效果是一样的。

总结

使用这条语句的目的是为了优化C++程序的输入输出性能,特别是在算法竞赛或性能敏感的应用中。这些语句通过减少iostream与stdio的同步以及解除cin和cout之间的绑定,来减少不必要的缓冲区刷新,从而提高程序的运行效率。

2.关闭同步流的注意事项:

① 关闭同步流后,不要用"endl",而是换用"\n"。

在C++中,endl是一个操纵符,它在输出流中插入一个换行符,并刷新输出缓冲区。这通常用于确保在调用endl后,所有输出都被写入到输出设备(如屏幕)上。

  • endl
    • 优点:确保输出立即显示。
    • 缺点:由于刷新输出缓冲区,可能会导致性能下降,尤其是在频繁的输出操作中。
      \n仅是一个字符,它代表换行符,用于在输出流中插入一个新行,但它不会刷新输出缓冲区。
  • \n
    • 优点:比endl更高效,因为它不会导致缓冲区刷新。
    • 缺点:在某些情况下,可能需要手动刷新缓冲区以确保输出。
      当使用ios::sync_with_stdio(false);关闭C++和C标准流的同步时,这意味着C++的IO操作不再与C的stdio库同步。这通常用于提高性能,特别是在处理大量输入输出操作时。在这种情况下,推荐使用\n而不是endl,因为同步已经关闭,且endl的缓冲区刷新操作不再必要,这样可以进一步提高性能。
② 不使用getchar() 而是换用cin.get()

getchar()是C标准库函数,用于从标准输入读取下一个字符,它忽略任何之前的换行符。
cin.get()是C++的iostream库成员函数,它也用于从输入流读取下一个字符,但它可以处理iostream流的状态和格式。
以下是两者的一些区别:

  • getchar()
    • 属于C标准库。
    • 不影响C++的iostream流状态。
    • 通常用于简单的字符读取。
  • cin.get()
    • 属于C++的iostream库。
    • 读取字符时会更新iostream流的状态。
    • 可以更灵活地用于C++的流操作。
      在关闭了stdio同步的情况下(ios::sync_with_stdio(false);),推荐使用cin.get(),因为它与C++的iostream库更加一致,可以更好地处理流的状态。在下面的代码中:
ios::sync_with_stdio(false);
string s;
cin >> s;
char c1 = cin.get();     //char c2=getchar();

在读取字符串s之后,使用cin.get()来读取并丢弃缓冲区中的换行符(如果有的话)。这是因为在读取字符串后,换行符通常留在输入流中。如果不处理这个换行符,它可能会干扰后续的输入操作。

而如果使用getchar(),它不会影响C++的iostream流状态,可能导致流状态不一致的问题。

2.cin.ignore( );

cin.ignore() 是 C++ iostream 库中的一个成员函数,用于忽略输入流中的字符。这个函数通常用于在读取输入之后清除输入缓冲区中的剩余字符,例如换行符、空白字符或其他不需要的字符。

基本语法

cin.ignore(n, delimiter);
  • n:表示要忽略的字符的最大数量。如果 n 被省略,则默认为 std::numeric_limits<std::streamsize>::max(),这意味着将忽略尽可能多的字符,直到遇到文件结束符(EOF)或者指定的 delimiter
  • delimiter:一个可选参数,表示遇到这个字符时停止忽略。如果 delimiter 被省略,则默认忽略所有字符直到 n 个字符被忽略或者到达文件结束。

示例

#include <iostream>
#include <limits>
int main() {
    std::string s;
    std::getline(std::cin, s); // 读取一行文本
    // 忽略接下来的10个字符或者直到遇到换行符
    std::cin.ignore(10, '\n');
    // 继续其他输入操作
    int number;
    std::cin >> number;
    return 0;
}

使用场景

  • 清除换行符:在读取一行文本后,通常会有一个换行符留在输入缓冲区中。使用 cin.ignore() 可以清除这个换行符,以免影响后续的输入操作。
  • 忽略特定字符:在某些情况下,你可能想要忽略输入流中的特定字符或字符序列,cin.ignore() 允许你指定一个终止字符来实现这一点。

注意事项

  • 流状态cin.ignore() 会根据读取的字符更新流的状态。如果遇到文件结束符(EOF),则设置 eofbit;如果遇到错误,则设置 failbit
  • 性能:如果指定了一个非常大的 n 值,cin.ignore() 可能会执行大量的读取操作,这可能会影响性能。
  • 缓冲区大小:使用 cin.ignore() 时,需要确保不会超出输入缓冲区的大小。

替代方案

在某些情况下,你可以使用其他方法来清除输入缓冲区:

  • cin.get():可以读取并丢弃缓冲区中的下一个字符。
  • cin.clear() 和 cin.ignore():通常结合使用,先清除错误标志(cin.clear()),然后忽略缓冲区中的剩余字符(cin.ignore())。

总之,cin.ignore() 是一个有用的工具,可以用来控制输入流,确保后续的输入操作能够正确进行。

上一篇:基于Python的人工智能应用案例系列(14):Fashion MNIST图像分类CNN


下一篇:NetApp 混合闪存 FAS 统一存储平台