简体   繁体   中英

Why does std::istream::ignore not return when called on an empty stream?

std::cin is a global object, and as such I always want to set it to a good state before using it. However, when invoking ignore() on an unused cin the function doesn't return.

See sample code below. Execution doesn't reach line 8 ( cout ) without user intervention. In my testing this behavior is consistent with or without the second argument (the delimiter, I've tried '\\n' and EOF).

I've been through a couple of online references, but I don't see why this happens.

#include <limits>
#include <iostream>
#include <string>
std::string readInput() {
    std::string input = "";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cout << "We never get here..." << std::endl;
    std::getline(std::cin, input);
    return input;
}
int main() {    
    std::string foo = readInput();  
}
  1. Why does ignore() not return in this case?
  2. How can I safely reset and empty std::cin before use?

See the second argument '\\n' . You are requesting to read characters up to and including a '\\n' and ignore them. Since there is no '\\n' on the stream, this means to block until one is received.

Hopefully it is clear that you should only make this call when it is known that there is a '\\n' on the stream.

So , the answer to your second question is that before use, do nothing , since there is no data on the stream anyway.

The time to clear the stream is after reading some data from it; and then depending on which read operation you used, you will know whether or not there is a newline.

Note that there is no such operation "clear whatever is on the stream" (this is intentional design). Instead your operations would be things like "clear the remainder of the line", where "the line" is defined as up to the next newline character; and input would have come from a file that uses lines, or an interactive terminal where the user presses Enter.

As stated in the documentation :

ignore behaves as an UnformattedInputFunction. After constructing and checking the sentry object, it extracts characters from the stream and discards them until any one of the following conditions occurs: [...] the next available character c in the input sequence is delim, as determined by Traits::eq_int_type(Traits::to_int_type(c), delim). The delimiter character is extracted and discarded. This test is disabled if delim is Traits::eof()

Therefore, it will trigger a call to underflow() of the corresponding stream buffer if the stream is empty, as ignore in your case is waiting for '\\n'.

Note: When you want to make sure your stream buffer is entirely empty, you may call cin.rdbuf()->in_avail() to get the amount of characters still waiting to be extracted from the input buffer, thus being 0 if the buffer is empty. This however is highly implementation-dependent, as it will work eg with Visual Studio out of the box. For GCC on the other hand, you have to call cin.sync_with_stdio(false) before in order to turn own the internal buffering. It will not work with LLVM like this, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM