【问题标题】:How to prevent `std::cin` or `\n` from flushing the buffer of `std::cout`?如何防止 `std::cin` 或 `\n` 刷新 `std::cout` 的缓冲区?
【发布时间】:2020-12-12 12:46:15
【问题描述】:

假设我的程序在不同时间需要用户输入。 我想要这个输入来防止刷新cout 缓冲区。 我可以在不同的流缓冲区上设置cincout 吗?

有问题的示例:一个程序读取一行中的两个数字n1 n2,并根据第一个数字是012

  • n1 = 0:将第二个数字n2 写入向量v
  • n1 = 1:在cout 中输出v[n2]
  • n1 = 2: pop_back() v

MWE 是:

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int size, n1, n2;
    vector<int> v;
    cin >> size;

    while(size--){
        cin >> n1;

        if (n1 == 0)
        {
            cin >> n2;
            v.push_back(n2);
        }
        else if (n1 == 1)
        {
            cin >> n2;
            cout << v[n2] << '\n';
        }   
        else if (n1 == 2)
            v.pop_back();
    }

return 0;
}

假设我有这个测试输入

8
0 1
0 2
0 3
2
0 4
1 0
1 1
1 2

正确的输出应该是

1
2
4

上面的程序产生了散布在输入行中的输出。

但我希望它们在结束程序时一起打印,而不使用不同的方式,例如将它们存储在某个容器等中。

所以我认为我应该对缓冲区进行操作,但是如何操作呢?

【问题讨论】:

  • std::endl 总是刷新它插入的流。这就是它的工作。
  • 默认情况下,cincouttie()'d 一起,因此读取输入将首先刷新任何待处理的输出。您可以致电cin.tie(nullptr) 取消tie()
  • @RemyLebeau:如果有的话,解绑的副作用是什么?
  • @Lingo -- 不,解绑并不能满足您的所有需求。它消除了交互式输入所需的强制刷新。它不会影响流的内部刷新。举个极端的例子,如果程序写了足够多的输出来填充输出缓冲区,那么下一次插入流将刷新缓冲区。而且您不想禁用它。

标签: c++ io iostream streambuf


【解决方案1】:

您可以写入自己的std::stringstream 缓冲区,然后在准备好后将其输出到std::cout

MWE:

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>

using std::cin;
using std::cout;
using std::istream;
using std::runtime_error;
using std::stringstream;
using std::vector;

static auto get_int(istream& in) -> int {
    int n;
    if (!(in >> n)) {
        throw runtime_error("bad input");
    }
    return n;
}

int main() {
    auto ss = stringstream();
    auto v = vector<int>();
    auto size = get_int(cin);

    while(size--) {
        auto n1 = get_int(cin);

        if (n1 == 0) {
            auto n2 = get_int(cin);
            v.push_back(n2);
        } else if (n1 == 1) {
            auto n2 = get_int(cin);
            ss << v[n2] << '\n';
        } else if (n1 == 2) {
            v.pop_back();
        }
    }

    cout << ss.str();
}

【讨论】:

  • 有趣,&lt;sstream&gt; 相当强大。当您可以只写int 时,为什么还要持续使用auto?我很好奇,因为这些不是一些过于复杂的自定义类型。
  • 我更喜欢使用auto,部分原因是它需要初始化,尤其是对于基本类型。
  • 或许这样更安全,但会混淆代码一点。
  • 我认为“混淆”更加陌生。一旦我习惯了它(在 C# 中使用 var),我发现代码更加清晰。
【解决方案2】:

无需修改缓冲区。除了cout &lt;&lt; v[n2],您可以将v[n2] 存储在第二个向量中并在循环外部打印出来。

【讨论】:

  • 感谢您的及时回复。如我在问题正文中所述,如果我不能/不想使用容器怎么办?有没有办法防止cin 刷新缓冲区?
  • 您可以写入自己的std::stringstream 缓冲区,然后在准备好后将其输出到std::cout
  • @Eljay:我想,想用 MWE 进一步阐述吗?
猜你喜欢
  • 2012-03-27
  • 2010-09-20
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
相关资源
最近更新 更多