C++ stream extraction operator overloading - c++

This is a question as to the philosophy (canonical design) of user-written C++ input stream extraction operators (>>).
Assume that on entry to the >> operator implementation (for a user-written class), the eof flag is already set for the input stream.
Should a user-written extraction operator (>>)
set the failure flag (because no instance of the desired object can be found)
should it just return to the caller with the eof flag still set.
If the second approach is used, it implies that the caller must always check the eof flag before any attempt is made to invoke the >> operator. The reason is that the >> operator might successfully extract an instance of the desired class and set the eof flag.
The original code follows. Based on the comments below, this code appears to be wrong. If eof is already set on input, the extraction operator will simply return with eof still set. It appears that if eof is set, but bad and fail are not set, then an extraction of a string should be done to set the fail bit. Of course, the fail bit can be set directly.
/* Implement the C/C++ >> (stream input) operator as a non-member
function */
std::istream &operator>>(std::istream& is, DecNumber &val) {
DecContext context{DecContext::defInit};
uint32_t status;
/* The true value below prevents whitespace from being skipped */
std::istream::sentry s(is, true);
std::string inStr;
/* Check if the input stream is in a good state. Just return to the
caller if the input stremm is not in a good state. The caller
must handle this condition. */
if(!s)
return is;
/* Get a string from the input stream. This string is converted to
a DecNumber below. Just return to the caller if this step causes
any stream related errors. Note that reaching the end of the
input is not a stream related error here. A decimal number might
be the absolute last thing in the stream. */
is >> inStr;
if (is.bad() || is.fail())
return is;
/* Try to convert the string to a DecNumber using the default context
value */
decNumberFromString(val.getDecVal(), inStr.c_str(), context.getDecCont());
status = context.DecContextGetStatus();
/* Remove a few status bits we don't care about */
status &= ~(DEC_Inexact + DEC_Rounded);
if (status)
is.setstate(std::ios_base::failbit);
return is;
}

You should implement solution 1.
When in doubt, just look at what's already being done. As you can see below, the fail bit is being set if we try to read from a stream in EOF state.
Note that EOF is not the only way to fail though. Try setting std::string vals = "52 43 A"; in the code below.
failbit should be set if for any reason, operator>> doesn't actually stream a value. EOF is just one of those reasons.
#include <sstream>
#include <iostream>
#include <string>
void print_stream (std::istream & print_me, int const & i)
{
std::cout << "i: " << i << "\n";
std::ios_base::iostate bits = print_me.rdstate();
std::cout << "good: " << (bits & std::ios_base::goodbit) <<
", bad: " << (bits & std::ios_base::badbit) <<
", fail: " << (bits & std::ios_base::failbit) <<
", eof: " << (bits & std::ios_base::eofbit) << "\n";
std::cout << "\n----------------------------\n\n";
}
int main (void)
{
std::string vals = "52 43";
std::istringstream iss(vals);
int i;
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
return 0;
}
Outputs
$ ./a.exe
i: 52
good: 0, bad: 0, fail: 0, eof: 0
----------------------------
i: 43
good: 0, bad: 0, fail: 0, eof: 2
----------------------------
i: 43
good: 0, bad: 0, fail: 4, eof: 2
----------------------------
i: 43
good: 0, bad: 0, fail: 4, eof: 2
----------------------------
Note that the typical read pattern loop is some variation of...
while (input >> var >> var2 >> var3)
{
// failbit is not set. All reads succeeded.
// Do Stuff
}
If you need to detect whether the fail happened at some point during reading of multiple values then yea, you need to be a little more sophisticated and do some testing like...
while (true)
{
if (input >> var)
{
// We successfully read first value
if (input >> var2 >> var3)
{
// We succesfully read all the values!
// Do stuff
}
else
{
ErrorLog ("Partial line read!");
break;
}
else
{
// Nothing else to read
break;
}
}

"If the second approach is used, it implies that the caller must always check the eof flag before any attempt is made to invoke the >> operator."
No, why do you think they need to do so?
"Should a user-written extraction operator (>>) set the failure flag (because no instance of the desired object can be found) or should it just return to the caller with the eof flag still set."
The latter option of course, you're not supposed to manage stream states in overloaded extraction operators, unless you add your own validation rules (e.g. for expecting specific character patterns with the std::string field). It will usually be done correctly with the sub extraction operations that the overloaded operator uses.
Supposed you have something like follows:
struct MyType {
std::string field1;
int field2;
double field3;
}
std::istream& operator>>(std::istream& is, MyType& myinstance) {
is >> field1;
is >> field2;
is >> field3;
return is;
}
Each of the extractions will set the fields to their default constructed values, in case the operator>>() fails, because the stream is in eof() state, and the value will be left in it's original state for the field that was attempted to extract.
I actually don't see a need to have any additional check for eof() or setting the stream to fail() state in your overloaded input operator.
The client (caller) will simply use something like e.g.
std::ifstream input("MyFile.txt");
std::vector<MyType> allObjects;
MyType curObject;
while(input >> curObject) {
allObjects.push_back(curObject);
}
You see, no need to check for input.eof() anywhere.

Related

insertion >> operator overload: exception handling when retrieving object's ctor parameters from cin

Here is an example of possible user input that is considered valid:
(-12.444,34.55) (2.0,-44.4444)
... invalid input, ) is missing:
(23.33,-234.5555 (-23.33, 44.1)
Complex.cpp : ctor
Complex (double real = 1.0, double imag = 0.0 );
Complex.cpp : Exception class
class Invalid_Mode1_Complex_Value: public std::invalid_argument {
public:
Invalid_Mode1_Complex_Value():std::invalid_argument("Invalid value for inputting Complex # using Mode 1"){}
};
insertion operator overload:
istream & operator >> (istream & input, Complex & obj) {
input.ignore(2,'('); // skip over '('
input >> obj.real_part; // read the real component of the Complex #
// Process ','
if (input.peek() == ',') {
input.get(); // swallow ','
}
else {
input.flags(origFormat); // restore format flags
input.clear();
throw Invalid_Mode1_Complex_Value();
}
// Process imaginary part
// read the imaginary component of the Complex #
input >> obj.imaginary_part;
// Process ')'
if (input.peek() == ')') {
input.get(); // swallow ')'
}
else {
input.flags(origFormat); // restore format flags
input.clear();
throw Invalid_Mode1_Complex_Value();
}
}
// restore format flags
input.flags(origFormat);
return input; // enables cin >> a >> b >> c
}
Main.cpp : try / catch :
Complex A,B; // Create Complex objects:
// My question is regarding the cascading objects in the try block
cout << "\nEnter 2 Complex numbers in the form \"(real_value,imaginary_value)\" :\n";
try
{
cin >> A >> B;
}
catch(const Invalid_Mode1_Complex_Value & invalidMode1Exception)
{
cerr << "\nException occurred: " << invalidMode1Exception.what() << endl;
}
I don't quite understand how exception handling occurs in the try block: cascading objects with the insertion operator. What are some scenarios that may occur and how to implement better practices.
A: if object A receives erroneous input
B: if object A is okay, however object B receives erroneous input
C: valid double values provided, however incorrect format is provided
If reading object A throws an exception, A is in some unknown state, B is left unchanged.
If reading object A succeeds but reading object B throws an exception, A is in a good state, B is in some unknown state
Well the incorrect formatting is where the exceptions are thrown. However, if the doubles can't be read, there will be some part left on the stream, and reading the formatting will fail.
You should add a check of the stream state after reading each double, to check it succeeded:
input >> obj.real_part;
if (!input) throw Invalid_Mode1_Complex_Value();
You should read up on exception safety guarantees. Here you can offer strong exception safety on the Complex by reading into some local variable, then assigning that into obj only if the read succeeds. (You still only offer basic exception safety on the stream).
std::stream& operator>> (std::istream& input, Complex& obj) {
Complex tmp;
// ...
input >> tmp.real_part;
if (!input) throw //...
// ...
obj = tmp; // if we got to here, we know tmp is properly formed
return input;
}

unexpected behavior when reading from istringstream

I have a question on the stream behavior, see the following example. What I was expecting is, since there are only 5 chars in the string, and stream read will get stuck as I am trying to read 10 chars. Instead, the output is "hellooooo" ... the last char get repeated.
My questions are two folds: first, why? second, is there anyway to make stream behave as if no more repeating of last char?
#include <sstream>
#include <iostream>
using namespace std;
int main(void) {
char c;
string msg("hello");
istringstream iss(msg);
unsigned int i = 0;
while (i < 10) {
iss >> c;
cout << c;
i++;
}
cout << endl;
return 0;
}
What you see is the result of reading form a stream in an erronous state. When you read past the last element in the stream (this being a string stream), the stream becomes erroneous and any other attempt to read from it will fail (and leave the extraction variable untouched).
You will have to check if the extraction operation succeeded before reading further:
if (iss >> c) {
// succeess
} else {
// failed to extract, handle error
}
Were you to use a stream connected to the console (for an example) your call to >> would have blocked as you expected. The behavior of stringstream is different (you cannot expect to micraculously contain more data)
The reason is that when you've read to the end of the stream, all attempts to read after that just fail, leaving the last value read in your c.
If you want to read at most 10 characters:
while (i < 10 && is >> c) {
cout << c;
i++;
}
This works because a stream can be converted to bool, and it's true if the stream is in a "good" state.
"the last char get repeated"
When iss >> c fails, c stays unmodified.
Check whether extraction of value succeeded by directly evaluating this expression: if (iss >> c), but don't even think about calling iss.good(). Check this answer and also have a look at:
How does that funky while (std::cin >> foo) syntax work?
Why does my input seem to process past the end of file?

C++: Check istream has non-space, non-tab, non-newline characters left without extracting chars

I am reading a std::istream and I need to verify without extracting characters that:
The stream is not "empty", i.e. that trying to read a char will not result in an fail state (solved by using peek() member function and checking fail state, then setting back to original state)
That among the characters left there is at least one which is not a space, a tab or a newline char.
The reason for this is, is that I am reading text files containing say one int per line, and sometimes there may be extra spaces / new-lines at the end of the file and this causes issues when I try get back the data from the file to a vector of int.
A peek(int n) would probably do what I need but I am stuck with its implementation.
I know I could just read istream like:
while (myInt << myIstream) {…} //Will fail when I am at the end
but the same check would fail for a number of different conditions (say I have something which is not an int on some line) and being able to differentiate between the two reading errors (unexpected thing, nothing left) would help me to write more robust code, as I could write:
while (something_left(myIstream)) {
myInt << myIstream;
if (myStream.fail()) {…} //Horrible things happened
}
Thank you!
There is a function called ws which eats whitespace. Perhaps you could call that after each read. If that hits eof, then you know you've got a normal termination. If it doesn't and the next read doesn't produce a valid int, then you know you've got garbage in your file. Maybe something like:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream infile("test.dat");
while (infile)
{
int i;
infile >> i;
if (!infile.fail())
std::cout << i << '\n';
else
std::cout << "garbage\n";
ws(infile);
}
}
this is what I did to skip whitespace/detect EOF before the actual input:
char c;
if (!(cin >> c)) //skip whitespace
return false; // EOF or other error
cin.unget();
This is independent of what data you are going to read.
This code relies on the skipws manipulator being set by default for standard streams, but it can be set manually cin >> skipw >> c;
And simple
for(;;){
if(!(myIstream >> myInt)){
if(myIstream.eof()) {
//end of file
}else{
//not an integer
}
}
// Do something with myInt
}
does not work? Why you need to know if there are numbers left?
Edit Changed to Ben's proposition.
The usual way to handle this situation is not to avoid reading from the stream, but to put back characters, which have been read, if needed:
int get_int(std::istream& in)
{
int n = 0;
while(true) {
if (in >> n)
return n;
clean_input(in);
}
}
void clean_input(std::istream& in)
{
if (in.fail()) {
in.clear();
// throw away (skip) pending characters in input
// which are non-digits
char ch;
while (in >> ch) {
if (isdigit(ch)) {
// stuff digit back into the stream
in.unget();
return;
}
}
}
error("No input"); // eof or bad
}

c++ validate number and stop infinity loop

I'm doing a console app, I'm passing an integer to the app and it works ok, but if I pass a letter, it goes crazy,
int opt=0;
std::cout<<"Pick lang:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;
while(opt<1 || opt>2)
{
std::cout<<"\nERROR!"<<'\n';
std::cout<<"Pick lang again:"<<'\n';
std::cout<<"1.[es-ES]:"<<'\n';
std::cout<<"2.[en-US]:"<<'\n';
std::cin >> opt;
}
I tried to use isdigit() but I get the same result. Thanks
After performing cin >> extraction, you want to check if the cin stream is still good or not. If you expect cin to extract a number but it gets something else instead, eg. like a letter, then the stream will be set to a bad state and that's why you see it 'going crazy'.
What you have to do is after input, check if cin is still good. If it's in a bad state, you need to clear its flags and then remove out any of the junk data in the stream. If you don't, then subsequent uses of cin will simply fail to function.
Taking your code snippet for example, you can change it to something like this:
int opt = 0;
bool inputGood = false;
do
{
std::cout << "Pick lang again:" << '\n';
std::cout << "1.[es-ES]:" << '\n';
std::cout << "2.[en-US]:" << '\n';
inputGood = std::cin >> opt;
if(!inputGood)
{
std::cout << "\nERROR! Invalid choice." << '\n';
cin.clear();
while( cin.get() != '\n' );
}
}while(!inputGood || opt < 1 || opt > 2);
Edit: whoops minor error in the cin error handling. Corrected and should be working now. :)
The problem is that the call std::cin >> opt is failing to parse the character and returns immediatly (without consuming the buffer), then it finds the same contents and fail....
You should check the result of the operation and react to it. One possibility would be checking the fail bit (std::cin.fail()) and failing the whole operation or consuming parts of the buffer (maybe a a single character, maybe more, depending on how you want the application to behave).
The simplest thing would probably be not reading into a number, but rather a character, and then comparing with the expected character:
char opt = 0;
do {
// prompt user for input
if (! (std::cin >> opt) ) {
// io error, report and bail out
break;
}
} while ( opt != '0' && opt != '1' );
Reading in numbers directly is
problematic
If std::cin is presented with input it
cannot process, std::cin goes into a
"fail" state The input it cannot
process is left on the input stream.
All input will be ignored by std::cin
until the "fail" state is cleared:
std::cin.clear()
A routine that reads
a number directly should:
Read in the
number
Check to see that the input
stream is still valid
If the input
stream is not good (!std::cin)
Call
std::cin.clear() to take the stream
out of the "fail" state.
Remove from
the stream the input that caused the
problem: std::cin.ignore(...)
Get the
input again if appropriate or
otherwise handle the error
more info here: http://www.augustcouncil.com/~tgibson/tutorial/iotips.html
When you insert a letter this happens:
operator>> extracts characters from the stream and try to convert them to a number;
it fails in the conversion, so it sets the stream state to ios::failbit and returns; opt probably is untouched (the standard delegates this stuff to the locale library, which is a zone of C++ that I never really understood - for the brave enough, it's at §22.2.2.1.2);
since it returned and (probably) opt is left as it is, the loop continues;
when the execution returns to std::cin >> opt;, operator>> sees that the state is still ios::failbit, so it doesn't even try to extract anything;
goto 3.
To fix the problem, you should clean the error state and remove the "wrong" characters from the input buffer. Since you probably don't want to add all that code to every cin>>, it's useful to create a function to deal with this common problem; personally, I created this little header (AcquireInput.hpp) that has proven useful many times:
#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED
#include <iosfwd>
#include <limits>
#include <string>
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
do
{
Os<<Prompt.c_str();
if(Is.fail())
{
Is.clear();
Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Is>>Result;
if(Is.fail())
Os<<FailString.c_str();
} while(Is.fail());
}
template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
InType temp;
AcquireInput(Os,Is,Prompt,FailString,temp);
return temp;
}
/* Usage example:
//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
*/
#endif

how to read stringstream with dynamic size?

I wanted to experiment with stringstream for an assignment, but I'm a little confused on how it works. I did a quick search but couldn't find anything that would answer my question.
Say I have a stream with a dynamic size, how would I know when to stop writing to the variable?
string var = "2 ++ asdf 3 * c";
stringstream ss;
ss << var;
while(ss){
ss >> var;
cout << var << endl;
}
and my output would be:
2
++
asdf
3
*
c
c
I'm not sure why I get that extra 'c' at the end, especially since _M_in_cur = 0x1001000d7 ""
You get the extra c at the end because you don't test whether the stream is still good after you perform the extraction:
while (ss) // test if stream is good
{
ss >> var; // attempt extraction <-- the stream state is set here
cout << var; // use result of extraction
}
You need to test the stream state between when you perform the extraction and when you use the result. Typically this is done by performing the extraction in the loop condition:
while (ss >> var) // attempt extraction then test if stream is good
{
cout << var; // use result of extraction
}
The while(ss) condition check in your code checks if the last read from the stream was successful or not. However, this check is going to return true even when you have read the last word in your string. Only the next extraction of ss >> var in your code is going to make this condition false since the end of the stream has been reached & there is nothing to extract into the variable var. This is the reason you get an extra 'c' at the end. You can eliminate this by changing your code as suggested by James McNellis.
There is also a member function good() which tests if the stream can be used for I/O operations. So using this the above code can be changed into
while(ss.good()) // check if the stream can be used for io
{
ss >> var; // attempt extraction <-- the stream state is set here
cout << var; // use result of extraction
}