0

I have a simple program that set unsigned int variable. Well, I have one problem. std::cout works fine until InputCLI is called.

First time program prints line when debugger reaches line that contain std::cout

std::cout << "debugNumber" << debugNumber;

After InputCLI call program prints lines only with \n untill it reaches std::cin operator. Whats wrong?

I'm coding in Eclipse (Linux). The moment before std::cin >> wait; was executed:

enter image description here

#include <iostream>
#include <limits>

unsigned int InputCLI(unsigned int& x);
int main() {
    int wait;
    unsigned int debugNumber = 0;
    std::cout << "debugNumber " << debugNumber;
    std::cout << "Enter debug number\n";
    InputCLI(debugNumber);
    std::cout << "debugNumber\n";
    std::cout << "debugNumber " << debugNumber;
    if (debugNumber == 6) {
        std::cout << "bubu";
    }
    std::cin >> wait;
    return 0;
}

unsigned int InputCLI(unsigned int& x) {
    if (std::cin >> x, std::cin.fail()) {
        if (std::cin.bad() || std::cin.eof())
            return -1;
        std::cin.clear();
        std::cin.ignore(std::numeric_limits < std::streamsize > ::max(), '\n');
        return -2;
    }
    return 0;
}
David G
  • 94,763
  • 41
  • 167
  • 253
maxi
  • 51
  • 1
  • 7

1 Answers1

2

If I dont add \n or std::endl std::cout will buffer data?

Yes, exactly.

std::flush explicitly flushes the stream. '\n' on its own doesn't do any flushing at the C++ level, but may trigger a flush at a lower level. std::endl prints a '\n' then does a std::flush.

Certainly, without any of those, you can't realistically expect a flush before your std::cin.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • `\n` cannot trigger a flush at a lower level because C++ is required not to pass it along to anywhere else until a `flush`. Also, it's worth noting that `<< std::flush` is also a valid way to express flushing, and more expository than `endl`. – Potatoswatter Apr 05 '14 at 19:41
  • @Potatoswatter: It's not required to but that doesn't mean it won't. There are multiple layers of buffering going on. – Lightness Races in Orbit Apr 05 '14 at 20:00
  • I said "required not to," not "not required to." If the text is stuck in the first buffer, it's not going anywhere else. – Potatoswatter Apr 05 '14 at 20:08
  • @Potatoswatter: Oh, is it really? It can't flush arbitrarily? – Lightness Races in Orbit Apr 05 '14 at 20:20
  • It never gets an opportunity to. The abstract base `std::basic_streambuf` does the buffering, and the `fstream` (or whatever) subclass only regains control on `overflow()`. The user can opt for *no* buffering, and that's the default for `std::cerr`, but that's a bit different. – Potatoswatter Apr 05 '14 at 20:22
  • @Potatoswatter: Why can't the `std::basic_streambuf` flush arbitrarily? – Lightness Races in Orbit Apr 05 '14 at 20:26
  • Because it's specified not to. It fills the buffer it's given, anything else would be broken and would probably cause the concrete implementation to flush uninitialized data. – Potatoswatter Apr 05 '14 at 20:27
  • @Potatoswatter: What if the buffer is filled before `std::flush` is called? I'm trying to demonstrate that a `std::flush`/`std::endl` is not the only circumstance under which data is flushed to the OS (or whatever the next layer down is). – Lightness Races in Orbit Apr 05 '14 at 20:30
  • `flush` invokes `sync` which is a different virtual method from `overflow`. A concrete subclass need not support `sync` at all and could just throw. `streambuf` is a bit crazy, but it's not allowed to be arbitrary, and thank God for that. – Potatoswatter Apr 05 '14 at 20:36
  • Yes, filling the buffer will cause a flush, but that's not related to a newline as the answer suggests. It's triggered by whatever character overflowed the buffer. – Potatoswatter Apr 05 '14 at 20:38
  • @Potatoswatter: It is related but not in the way you've interpreted. If a block of arbitrary characters ends up being flushed by the IOStream, because the buffer was filled, then those characters are sent to the next layer down. That layer may then choose to flush on any `\n` found within that block of bytes if it is using line buffering (as many terminals do by default). In this scenario the final outcome, as observed by the user, is a flush to screen at the point that a `\n` is written. – Lightness Races in Orbit Apr 06 '14 at 02:28
  • _(cont.)_ Though, yes, this not "reliable" because it will only occur if the IOStream buffer had been maxed out in the first place. That's where the word "may" comes in, in the relevant passage in my answer. – Lightness Races in Orbit Apr 06 '14 at 02:31
  • Have you even referred to the standard? No, there `streambuf` is not allowed to modify the pointers which define the buffer before calling `overflow`. There's no maybe about it. – Potatoswatter Apr 06 '14 at 03:39
  • @Potatoswatter: Huh? I didn't say it was! Are you not aware that IOStream semantics are not the only mechanism at play here? I'm starting to wonder... – Lightness Races in Orbit Apr 06 '14 at 03:44
  • `streambuf` takes bytes to be written and puts them directly in the buffer. There is no point for customization and no latitude for implementation variance. No other layer of implementation has access to the data until `overflow` or manual `flush` occurs. So no, there is no other mechanism at play. – Potatoswatter Apr 06 '14 at 06:07
  • @Potatoswatter: Overflow is precisely what I am talking about. I never said anything about customisation. I can't tell whether you're being deliberately obtuse. – Lightness Races in Orbit Apr 06 '14 at 12:41
  • You mean that `\n` may be flushed normally from C++, after a few kilobytes, and then subsequently cause a flush of a line-oriented output device. Yes, but that's certainly not happening in OP's code which only outputs a few bytes. As for obtuseness, you quietly changed your argument at "It is related but not in the way you've interpreted." There was nothing to indicate you were talking about something completely different at that point. – Potatoswatter Apr 07 '14 at 02:17
  • @Potatoswatter: It's what I've been talking about quite clearly the entire time, and it's what my answer says. At no stage did I say it was the OP's problem: again, my answer clearly says that this is what is _not_ happening. I'll leave you now to read it again because I won't argue against a strawman or a non sequitur. I have better things to do! (marginally) :) – Lightness Races in Orbit Apr 07 '14 at 07:28
  • "Oh, is it really? It can't flush arbitrarily?" — Keep the topic straight. – Potatoswatter Apr 07 '14 at 07:36
  • @Potatoswatter: You're misunderstanding again, and I don't see why. It's pretty clear. Contrary to my understanding, which I spelt out, and which you finally agreed to five hours ago, your early comments indicated that data in an IOStream could _only_ be flushed to OS when `std::flush` were called (which is obviously false when you consider the buffer filling up). So, my response to that was an incredulous "oh, is it really?" Please stop being so obtuse. This is not complicated. – Lightness Races in Orbit Apr 07 '14 at 07:49
  • OP example will not overflow so I didn't mention that irrelevant case. Try playing with `std::cerr` and you will likely find that what is unbuffered at the C++ level is likely unbuffered the rest of the way up the stack too. You're insisting that hypothetical situations are realistic. I'm being realistic, not obtuse. – Potatoswatter Apr 07 '14 at 07:53
  • I'm not "insisting" anything. We're talking about how streams work. At least, I am. I'm going to leave this thread be now: have a good day! – Lightness Races in Orbit Apr 07 '14 at 11:52