How would one generalise `clearerr()` under C++?… - c++

TL;DR
I am aware that if a program listens for EOF (e.g. ^D) as a sign to stop taking input, e.g. by relying on a conditional like while (std::cin) {...}, one needs to call cin.clear() before standard input can be read from again (readers who'd like to know more, see this table).
I recently learned that this is insufficient, and that the underlying C file descriptors, including stdin, need clearerr() to be run to forget EOF states.
Since clearerr() needs a C-style file descriptor, and C++ operates mainly with std::basic_streambufs and the like (e.g. cin), I want to generalise some code (see below) to run clearerr() on any streambuf's associated C-style file-descriptor, even if that may not be stdin.
EDITS (1&2):
I wonder if stdin is the only ever file-descriptor that behaves like this (needing clearerr() to run) ...?
If it isn't, then the following code should end the question of generalisation (idea pointed out by zkoza in their answer)
As zkoza pointed out in their comment below, stdin is the only file-descriptor that would, logically, ever need such treatment (i.e. clearerr()). Checking whether a given C++ stream is actually really attached to *std::cin.rdbuf() is all that is needed:
std::istream theStream /* some stream with some underlying streambuf */
if (theStream.rdbuf() == std::cin.rdbuf())
clearerr(stdin);
Background
I'm writing a tool in C++ where I need to get multiple lines of user input, twice.
I know there are multiple ways of getting multiline input (e.g. waiting for double-newlines), but I want to use EOF as the user's signal that they're done — not unlike when you gpg -s or -e.
After much consultation (here, here, and on cppreference.com), I decided to use... (and I quote the third):
[the] idiomatic C++ input loops such as [...]
while(std::getline(stream, string)){...}
Since these rely on std::basic_ios::operator bool to do their job, I ensured that cin.rdstate() was cleared between the first and second user-input instructions (using cin.clear()).
The gist of my code is as follows:
std::istream& getlines (std::basic_istream<char> &theStream,
std::vector<std::string> &stack) {
std::ios::iostate current_mask (theStream.exceptions());
theStream.exceptions(std::ios::badbit);
std::string &_temp (*new std::string);
while (theStream) {
if (std::getline(theStream, _temp))
stack.push_back(_temp); // I'd really like the input broken...
// ... into a stack of `\n`-terminated...
// ... strings each time
}
// If `eofbit` is set, clear it
// ... since std::basic_istream::operator bool needs `goodbit`
if (theStream.eof())
theStream.clear(theStream.rdstate()
& (std::ios::failbit | std::ios::badbit));
// Here the logical AND with
// ... (failbit OR badbit) unsets eofbit
// std::getline sets failbit if nothing was extracted
if (theStream.fail() && !stack.size()) {
throw std::ios::failure("No input recieved!");
}
else if (theStream.fail() && stack.size()) {
theStream.clear(theStream.rdstate() & std::ios::badbit);
clearerr(stdin); // 👈 the part which I want to generalise
}
delete &_temp;
theStream.exceptions(current_mask);
return theStream;
}

This does what you need:
#include <iostream>
int main()
{
std::cin.sync_with_stdio(true);
char c = '1', d = '1';
std::cout << "Enter a char: \n";
std::cin >> c;
std::cout << (int)c << "\n";
std::cout << std::cin.eof() << "\n";
std::cin.clear();
clearerr(stdin);
std::cout << std::cin.eof() << "\n";
std::cout << "Enter another char: \n";
std::cin >> d;
std::cout << (int)d << "\n";
std::cout << std::cin.eof() << "\n";
}
It works because C++'s std::cin is tied, by default, with C's stdin (so, the first line is actually not needed). You have to modify your code to check if the stream is std::cin and if so, perform clearerr(stdin);
EDIT:
Actually, sync_with_stdio ensures only synchronization between the C and C++ interfaces, but internally they work on the same file descriptors and this may be why clearerr(stdin); works whether or not the interfaces are tied by sync_with_stdio
EDIT2: Does these answer your problem? Getting a FILE* from a std::fstream
https://www.ginac.de/~kreckel/fileno/ ?

Related

C++ Why diff EOF checks recommended for text vs numeric?

My textbook recommends using the member accessor method iStreamVar.eof() when dealing with textual data and while (iStreamVar) when dealing with numeric data.
Can someone please explain why it would matter?
Quote from book:
Using the function eof to determine the end-of-file status works best if the input is text. The earlier method of determining the end-of-file status works best if the input consists of numeric data.
That is the only thing mentioned on the topic. After this, it just explains how the process works.
Which method you use for determining the end of data depends on how you use it. My guess is, both methods which your textbook mentions are used wrong, so they fail in different situations. That's why it recommends using different methods in different situations.
The correct method is not trivial, and it depends on how important error resilience is for you.
If you want to read a space-delimited stream with numbers in it, and you are sure the file contains no errors, the code is simplest:
int value;
while (iStreamVar >> value)
{
...
}
Note that it's not any of the two original options.
If your file contains space-delimited textual data, and you are sure there are no errors, use the same code (but declare the temporary variable as string instead of int).
If you want to detect and recover from errors, use more elaborate code. But I cannot recommend you any specific code structure - it depends on what exactly you want to do in case of errors. Also:
Are text records delimited by space or newline?
What if the input text-file contains an empty line?
Numbers - floating-point or not?
Numbers - if there is a stray character like a among number data, what to do?
So there is no single correct recipe for doing proper input with error resilience.
Unless there is something significant in the context that isn't shown in the question, that quote is nonsense.
The way to read from a file and check for success is to read from the file:
int data;
if (std::cin >> data)
std::cout << "read succeeded, value is " << data << '\n';
std::string data;
if (std::cin >> data)
std::cout << "read succeeded, value is " << data << '\n';
std::string data;
if (std::getline(std::cin, data)
std::cout << "read succeeded, value is " << data << '\n';
If an attempted read fails you can call .eof() to find out whether the failure was because the input was at the end of the file. Contrary to what some beginners expect (and what some languages do), if .eof() returns false it does not mean that there is data remaining in the input stream. The stream might be at the end of the file after a successful read consumed the remaining input. .eof() will return false, but the next attempted read will fail, and after that, .eof() will return true.
std::stringstream input("1234");
int data;
input >> data; // succeeds
std::cout << input.eof() << '\n'; // outputs 0, no failure
input >> data; // fails, no more input
std::cout << input.eof() << '\n'; // outputs 1, failed because at end of file

Why is the c++ input file stream checked twice here?

Here is a snippet from a c++ tutorial:
// istream::get example
#include <iostream> // std::cin, std::cout
#include <fstream> // std::ifstream
int main () {
char str[256];
std::cout << "Enter the name of an existing text file: ";
std::cin.get (str,256); // get c-string
std::ifstream is(str); // open file
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
if (is.good())
std::cout << c;
}
is.close(); // close file
return 0;
}
Notice is.good() appeared twice, first with while, then with if.
Link to the example: http://www.cplusplus.com/reference/istream/istream/get/
Why is the c++ input file stream checked twice here?
The fact of the matter is that it is unnecessarily checked twice. If the second inner if (is.good()) passes, then the outer while (is.good()) will always pass as well. The author of the code needed some way of looping, and he incorrectly assumed that a while (is.good()) is an appropriate condition because it will stop the loop when the stream fails to extract. But this is only half-true. while (is.good()) is never the correct way to perform the extraction.
You have to perform the input first and then check if it succeeded. Otherwise it is possible to perform a failed extraction, use the result of that extraction and receive unwanted behavior from your program. The correct way to do it is by using the extraction itself as the condition. The input operator will return a reference to the stream, and then it will turn into a boolean returning true if the previous read suceeded, or false otherwise:
while (is.get(c))
{
std::cout << c;
}
The variable c is also not outside of the loop. You can enclose the while() loop in a block or use a for() loop instead:
for (char c; is.get(c); )
{
std::cout << c;
}
But it seems that this code is attempting to write all the content from the file to standard output. Reading a character one-by-one is the way shown here, but you can also use stream iterators or the buffer overload of std::ostream::operator<<() as well.
There are two more problems I see in this code. Namely:
std::string is the preferred construct for manipulating dynamically-sized strings, not C-style strings which require the use of archaic input methods such as .get(), .getline(), etc, and their respective overloads.
Manually closing a file is usually unneeded. The stream will close itself at the end of the scope in which it was created. You probably only want to close the file yourself to check if it succeeds or to reopen the stream with a different file or openmode.
The first one, that in while (is.good()), checks if it has reached EOF (End Of File). If not, it doesn't enter the while loop. Once entered in while(), it means that it have at least one character remained for the instruction char c = is.get();.
What the second if() does is that it doesn't allow to print the last character read, because after a char c = is.get();, the file may reach EOF. In case it does, the character is not printed.
For example, let's say you have this file:
"Just an example!"
Now, if you had just:
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
std::cout << c;
}
the output would be: "Just an example! ". The last space is the EOF character (which is the last character read).
But with:
while (is.good()) // loop while extraction from file is possible
{
char c = is.get(); // get character from file
if (is.good())
std::cout << c;
}
the output would be: "Just an example!", which is what you would expect it to be.

istream::unget() in C++ doesn't work as I thought

unget isn't working the way I thought it would... Let me explain myself. As I think, unget takes the last character extracted in the stream and it puts it back in the stream (and ready to be extracted again). Internally, it's decreasing the pointer in the stream buffer (creating the sentry and all that stuff).
But, when I use two unget() one behind the other, it's behaviour get deeply strange. If write something like hello<bye, and I use < as a delimiter, if I use getline and later two ungets, it returns me hello, and no o<bye". This is my code:
#include <iostream>
#define MAX_CHARS 256
using namespace std;
int main(){
char cadena[MAX_CHARS];
cout << "Write something: ";
cin.getline(cadena, MAX_CHARS, '<');
cout << endl << "Your first word delimited by < is: " << cadena << endl;
cin.unget(); //Delimiter (removed by getline) is put back in the stream
cin.unget(); //!?
cin >> cadena;
cout << "Your phrase with 2 ungets done..." << cadena;
return 0;
}
Try with bye<hello, then cadena gets bye and not e<hello I thought that unget works with the last one character each time it's called, what the f*** is happening?
The problem you are observing isn't surprising at all. First off, note that ungetting characters may or may not be supported by the underlying stream buffer. Typically, at least one character of putback is supported. Whether this is actually true and if any more characters are supported is entirely up to the stream buffer.
What happens in your test program is simply that the second unget() fails, the stream goes into failure state (i.e., std::ios_base::failbit is set) and another attempt to read something just fails. The failed read leave the original buffer unchanged and since it isn't tested (as it should), it looks as if the same string was read twice.
The fundamental reason std::cin is likely to support only one character to be put back is that it is synchronized with stdin by default. As a result, std::cin doesn't do any buffer (causing it to be rather slow as well for that matter). There is a fair chance that you can get better results by no synchronizing with stdin:
std::ios_base::sync_with_stdio(false);
This will improve the performance and the likelihood of putting more characters being successful. There is still no guarantee that you can put multiple character (or even just one character) back. If you really need to put back character, you should consider using a filtering stream buffer which supports as many character puthback as you need. In general, tokenizing input doesn't require any characters of putback which is the basic reason that there is only mediocre support: since putback support is bad, you are best off using proper tokenizing which reduces the need to improve putback. Somewhat of a circular argument. Since you can always create your own stream buffer it isn't really harmful, though.
The actuall reason for this behaviour is related to the failbits of stream as explained in previous answer. I can provide a work around code that may help you in achieving the results you want.
#include <iostream>
#include <boost/iostreams/filtering_stream.hpp>
// compile using g++ -std=c++11 -lboost_iostreams
#define MAX_CHARS 256
using namespace std;
int main(){
boost::iostreams::filtering_istream cinn(std::cin,0,1);
char cadena[MAX_CHARS];
cout << "Write something: ";
cinn.getline(cadena, MAX_CHARS, '<');
cout << endl << "Your first word delimited by < is: " << cadena << endl;
cinn.unget(); //Delimiter (removed by getline) is put back in the stream
cinn.unget(); //!?
cinn >> cadena;
cout << "Your phrase with 2 ungets done..." << cadena;
return 0;
}

Find the end of stream for cin & ifstream?

I'm running myself through a C++ text book that I have as a refresher to C++ programming. One of the practice problems (without going into too much detail) wants me to define a function that can be passed ifstream or cin (e.g. istream) as an argument. From there, I have to read through the stream. Trouble is, I can't figure out a way to have this one function use cin and ifstream to effectively find the end of the stream. Namely,
while(input_stream.peek() != EOF)
isn't going to work for cin. I could rework the function to look for a certain phrase (like "#End of Stream#" or something), but I think this is a bad idea if the file stream I pass has this exact phrase.
I have thought to use function overloading, but so far the book has mentioned when it wants me to do this. I'm probably putting too much effort into this one practice problem, but I enjoy the creative process and am curious if there's such a way to do this without overloading.
eof() does work for cin. You are doing something wrong; please post your code. One common stumbling block is that eof flag gets set after you try to read behind the end of stream.
Here is a demonstration:
#include <iostream>
#include <string>
int main( int, char*[] )
{
std::string s;
for ( unsigned n = 0; n < 5; ++n )
{
bool before = std::cin.eof();
std::cin >> s;
bool after = std::cin.eof();
std::cout << int(before) << " " << int(after) << " " << s << std::endl;
}
return 0;
}
and its output:
D:>t
aaaaa
0 0 aaaaa
bbbbb
0 0 bbbbb
^Z
0 1 bbbbb
1 1 bbbbb
1 1 bbbbb
(EOF can be generated with Ctrl-Z on Windows and Ctrl-D on many other OSes)
Why won't std::cin.eof() work? cin will signal EOF when stdin closes, which will happen when the user signals it with Ctrl+d (*nix) or Ctrl+z (Windows), or (in the case of a piped input stream) when the piped file ends
If you use a stream in a boolean context then it will convert itself into a value that is equivalent to true if it has not reached the EOF and false if an attempt has been made to read past the EOF (not it is also false if there was a previous error reading from the stream).
Since most IO operations on streams return the stream (so they can be chained). You can do your read operation and use the result in the test (as above).
So a program to read a stream of numbers from a stream:
int main()
{
int x;
// Here we try and read a number from the stream.
// If this fails (because of EOF or other error) an internal flag is set.
// The stream is returned as the result of operator>>
// So the stream is then being used in the boolean context of the while()
// So it will be converted to true if operator>> worked correctly.
// or false if operator>> failed because of EOF
while(std::cin >> x)
{
// The loop is only entered if operator>> worked correctly.
std::cout << "Value: " << x << "\n";
}
// Exit when EOF (or other error).
}

How do I flush the cin buffer?

How do I clear the cin buffer in C++?
I would prefer the C++ size constraints over the C versions:
// Ignore to the end of Stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max())
// Ignore to the end of line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
Possibly:
std::cin.ignore(INT_MAX);
This would read in and ignore everything until EOF. (you can also supply a second argument which is the character to read until (ex: '\n' to ignore a single line).
Also: You probably want to do a: std::cin.clear(); before this too to reset the stream state.
cin.clear();
fflush(stdin);
This was the only thing that worked for me when reading from console. In every other case it would either read indefinitely due to lack of \n, or something would remain in the buffer.
EDIT:
I found out that the previous solution made things worse. THIS one however, works:
cin.getline(temp, STRLEN);
if (cin.fail()) {
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
I have found two solutions to this.
The first, and simplest, is to use std::getline() for example:
std::getline(std::cin, yourString);
... that will discard the input stream when it gets to a new-line. Read more about this function here.
Another option that directly discards the stream is this...
#include <limits>
// Possibly some other code here
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Good luck!
int i;
cout << "Please enter an integer value: ";
// cin >> i; leaves '\n' among possible other junk in the buffer.
// '\n' also happens to be the default delim character for getline() below.
cin >> i;
if (cin.fail())
{
cout << "\ncin failed - substituting: i=1;\n\n";
i = 1;
}
cin.clear(); cin.ignore(INT_MAX,'\n');
cout << "The value you entered is: " << i << " and its double is " << i*2 << ".\n\n";
string myString;
cout << "What's your full name? (spaces inclded) \n";
getline (cin, myString);
cout << "\nHello '" << myString << "'.\n\n\n";
How about:
cin.ignore(cin.rdbuf()->in_avail());
I prefer:
cin.clear();
fflush(stdin);
There's an example where cin.ignore just doesn't cut it, but I can't think of it at the moment. It was a while ago when I needed to use it (with Mingw).
However, fflush(stdin) is undefined behavior according to the standard. fflush() is only meant for output streams. fflush(stdin) only seems to work as expected on Windows (with GCC and MS compilers at least) as an extension to the C standard.
So, if you use it, your code isn't going to be portable.
See Using fflush(stdin).
Also, see http://ubuntuforums.org/showpost.php?s=9129c7bd6e5c8fd67eb332126b59b54c&p=452568&postcount=1 for an alternative.
Another possible (manual) solution is
cin.clear();
while (cin.get() != '\n')
{
continue;
}
I cannot use fflush or cin.flush() with CLion so this came handy.
Easiest way:
cin.seekg(0,ios::end);
cin.clear();
It just positions the cin pointer at the end of the stdin stream and cin.clear() clears all error flags such as the EOF flag.
It worked for me. I have used for loop with getline().
cin.ignore()
The following should work:
cin.flush();
On some systems it's not available and then you can use:
cin.ignore(INT_MAX);
#include <stdio_ext.h>
and then use function
__fpurge(stdin)
cin.get() seems to flush it automatically oddly enough (probably not preferred though, since this is confusing and probably temperamental).
fflush(stdin) − It is used to clear the input buffer memory. It is recommended to use before writing scanf statement.
fflush(stdout) − It is used for clearing the output buffer memory. It is recommended to use before printf statement.
The following should work:
cin.flush();
On some systems it's not available and then you can use:
cin.ignore(INT_MAX);
Both Windows and Linux define the behaviour of fflush() on an input stream,
and even define it the same way (miracle of miracles).
The POSIX, C and C++ standards for fflush() do not define the behaviour,
but none of them prevent a system from defining it.
If you're coding for maximum portability, avoid fflush(stdin);
if you're coding for platforms that define the behaviour, use it — but be aware that it is not portable
portable code does not use fflush(stdin). Code that is tied to Microsoft's platform may use it and
it may work as expected, but beware of the portability issues.