I have two questions on the following simple code:
/*
test.cpp
© BS.
Example of creation of a class of a flow for which it is possible to assign the additional
characters interpreted as separators.
11/06/2013, Раздел 11.7
*/
//--------------------------------------------------------------------------------------------------
#include <iostream>
#include <sstream>
#include <algorithm>
#include <exception>
#include <string>
#include <vector>
using namespace std;
//--------------------------------------------------------------------------------------------------
class Punct_stream
// it is similar to istream flow, but the user can independently set separators.
{
private:
istream& source; // source of chars
istringstream buffer; // buffer for formatting
string white; // whitespaces
bool sensitive; // case sensitive
public:
Punct_stream(istream& is): source(is), sensitive(true) {}
void whitespace(const string& s) { white = s; }
void add_white(char c) { white += c; }
void case_sensitive(bool b) { sensitive = b; }
bool is_case_sensitive() { return sensitive; }
bool is_whitespace(char c);
Punct_stream& operator >> (string& s);
operator bool();
};
//--------------------------------------------------------------------------------------------------
bool Punct_stream::is_whitespace(char c)
// is the c a whitespace?
{
for(int i = 0; i < white.size(); ++i) if(c == white[i]) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
Punct_stream::operator bool()
// check the input result
{
return !(source.fail() || source.bad()) && source.good();
}
//--------------------------------------------------------------------------------------------------
Punct_stream& Punct_stream::operator >> (string& s){
while(!(buffer >> s)){ // try to read the data from the buffer
if(buffer.bad() || !source.good()) return *this;
buffer.clear();
string line;
getline(source,line); // read the line from the source
// if necessary we replace characters
for(int i = 0; i < line.size(); ++i)
if(is_whitespace(line[i])) line[i] = ' ';
else if(!sensitive) line[i] = tolower(line[i]);
buffer.str(line); // write a string line to the stream
}
return *this;
}
//==================================================================================================
int main()
// entry point
try{
Punct_stream ps(cin);
ps.whitespace(";:,.?!()\"{}<>/&$##%^*|~");
ps.case_sensitive(false);
cout << "Enter the words, please: ";
vector<string> vs;
string word;
while(ps >> word) vs.push_back(word); // enter words
sort(vs.begin(), vs.end());
// we delete counterparts
for(int i = 0; i < vs.size(); ++i) if(i == 0 || vs[i] != vs[i-1]) cout << vs[i] << endl;
}
catch(exception& e){
cerr << e.what() << endl;
return 1;
}
catch(...){
cerr << "Unknown exception." << endl;
return 2;
}
The checking in the Punct_stream::operator bool() function is not clear for me:
return !(source.fail() || source.bad()) && source.good();
My questions:
Why author checked the 'fail' and the 'bad'? Why it wasn't restricted the 'good' check only? Unless the positive 'good' automatically doesn't imply, what 'fail' and 'bad' are set in 'false' value?
Besides, often in a code write such construction:cin >> x; while(cin){//...}
Why the author didn't write by analogy so:
Punct_stream::operator bool()
// check the input result
{
// return !(source.fail() || source.bad()) && source.good();
return source;
}
The alternative option shown by me doesn't work for me (Windows crashed), it would be desirable to understand why, what I missed?
Thank you.
The istream object contains a bunch of bit flags that represent its internal status. Of them, the ones that interests you are:
eofbit End-Of-File reached while performing an extracting operation on an input stream.
failbit The last input operation failed because of an error related to the internal logic of the operation itself.
badbit Error due to the failure of an input/output operation on the stream buffer.
goodbit No error. Represents the absence of all the above (the value zero).
Their status is represented in the following table
good() eof() fail() bad()
goodbit No errors (zero value iostate) true false false false
eofbit End-of-File reached on input operation false true false false
failbit Logical error on i/o operation false false true false
badbit Read/writing error on i/o operation false false true true
Respectively, good() returns the goodbit, eof() checks the eofbit, fail() checks the failbit, and, surprisingly, bad() returns the badbit.
So depending on what you are doing, each function could be used in a different settings.
However, in your case, simply checking the trueness of the good bit would be enough, as it is true when the others are all false. Testing at the same time the failbit or the badbit is redundant.
source: http://www.cplusplus.com/reference/ios/ios/
EDIT:
Actually I'm not really sure why your alternative wouldn't work, as it works for me. What data did you exactly pass to the program?
Related
Made something like this:
int main()
{
while (true)
{
std::cout << "Enter a number between one and nine. \n";
int oneandnine;
std::cin >> oneandnine;
if (std::cin.fail())
{
std::cin.clear();
std::cin.ignore(100, '\n');
std::cout << "INVALID UNPUT!\n";
}else if (oneandnine <= 9 && oneandnine >= 1)
{
break;
}else
{
std::cout << "INVALID UNPUT!\n";
}
}
return 0;
}
and when input is provided something like this 456aihdb, getting something like this:
INVALID UNPUT!
Enter a number between one and nine.
INVALID UNPUT!
Enter a number between one and nine.
Why does it loop twice like this? is it because when the 456 is discarded and the rest aihdb isn't which causes it to loop again and skip a cin input?
It is exactly as you think it is.
The fail flag isn't set immediately, instead the formatted input operator reads the integer 456 into oneandnine, but doesn't set the fail flag since it's a valid integer value. That leads to the else case executing since std::cin.fail() is false and oneandnine is not between 1 and 9.
The next iteration you read the invalid input and the fail flag will be set leading to the second error output.
One common way to handle validation is to read the whole line into a string, put that string into an std::istringstream and use that to attempt to parse the input:
if (!std::getline(std::cin, line))
{
// Failure of some kind, could be EOF or something else
// Probably best not to continue in this case
}
std::istringstream iss(line);
if (!(iss >> oneandnine))
{
// Invalid input, report it as such
}
if (oneandnine < 1 || oneandnine > 9)
{
// Invalid number, report it as such
}
// Correct input, continue with program
Note that input such as 6abc will be considered valid by the above code. The 6 will be extracted into oneandnine and the abc part will silently be discarded. If that's not wanted there are other ways for the parsing (e.g. std::stoi or std::strtol if exceptions are not wanted). Do that instead of the >> extraction, but the rest of the code above should be fine.
std::istream's operator >> doesn't read in whole lines. It reads until it finds an invalid character or whitespace, if it has found a valid character before the invalid character the read operation succeeds and the invalid character is left in the stream.
In your example the first iteration successfully reads 456 and leaves aihdb in the stream. This fails your range check and the second iteration then tries to read the remaining characters which fails as the first character isn't a number.
If you want to read whole lines use std::getline then parse the whole line into a number. For example:
#include <iostream>
#include <string>
using std::cout;
int main()
{
while (true)
{
std::cout << "Enter a number between one and nine. \n";
std::string line;
std::getline(std::cin, line);
int oneandnine;
size_t pos;
try
{
oneandnine = std::stoi(line, &pos);
}
catch ( std::exception& )
{
oneandnine = -1;
}
if (pos != line.size() || oneandnine > 9 || oneandnine < 1)
{
std::cout << "INVALID INPUT!\n";
}
else
{
break;
}
}
return 0;
}
I want this code to check whether the input is an int or not, and it works fine until I enter a float type number. I need a program that won't let through float numbers.
bool error;
int x;
string s;
do
{
cout <<"number: ";
cin >> x;
error=cin.fail();
if(error)
{
cout << "error" <<endl;
cin.clear();
}
getline(cin,s);
}while(error);
cout << x;
Read in all of the user's input line as a string, then convert the string to an integer with std::stoi.
Unfortunately std::stoi will happily stop converting when it hits the end of convertible characters, but it allows you to pass in a pointer to a position to be updated with the character that ended the conversion. If this position is not the end of the string, there was garbage on the line.
bool error = true; // assume user input is wrong
while (error)
{
if (std::getline(std::cin, s)) // grab the whole line
{
std::size_t end;
try
{
x = std::stoi(s, &end);
if (end == s.length()) // converted all user input
{
error == false; // good data
}
}
catch(std::invalid_argument &) // user input is complete garbage
{
}
catch(std::std::out_of_range &) // converted user input is too big for int.
{
}
}
}
^
I recommend turning the input loop into a function. 1) It's easily reusable should you need to convert an int again. 2) It gets rid of some of the logic above because you can return when the input is tested and good.
int gimmieInt(std::istream& in) // Me eat input stream! Om nom nom nom!
{
std::string s;
int x;
while (true) // consider instead using a maximum number of retries.
// This increases complexity, so consider it *after* you have
// the basic version working
{
if (std::getline(in, s))
{
std::size_t end;
try
{
x = std::stoi(s, &end);
if (end == s.length())
{
return x;
}
}
catch(std::invalid_argument &) // user input is complete garbage
{
}
catch(std::std::out_of_range &) // user input is too big for int.
{
}
}
}
}
std::istream& operator(std::istream&, int) will read a valid integer number up to any non matching character like '.', and no error state is set for the stream up to this point.
You better should read complete (whitespace separeated) chunks as std::string, and inspect them if these contain the desired format (e.g. using std::regex).
std::stoi() should also fail with an exception, if you're trying to convert the chunk.
I think, you are looking for something like this (C++11):
auto s = std::string{};
std::cin >> s;
if( std::all_of(std::begin(s), std::end(s),
[](char c) -> bool {
return c <= '0' && c <= '9';
}) ) {
std::cout << "you have entered an integer" << std::endl;
}
Somehow I thought, that the standard library contains a predicate that checks if a given char is a digit, but I could not find it now. Such a hypothetic is_digit() would allow make the code more readable:
if( std::all_of(std::begin(s), std::end(s), std::hypothetic::is_digit) ) {
std::cout << "you have entered an integer" << std::endl;
}
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.
My question is very similar to a previous one. I want to open and read a file. I want exceptions thrown if the file can't be opened, but I don't want exceptions thrown on EOF. fstreams seem to give you independent control over whether exceptions are thrown on EOF, on failures, and on other bad things, but it appears that EOF tends to also get mapped to the bad and/or fail exceptions.
Here's a stripped-down example of what I was trying to do. The function f() is supposed to return true if a file contains a certain word, false if it doesn't, and throw an exception if (say) the file doesn't exist.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool f(const char *file)
{
ifstream ifs;
string word;
ifs.exceptions(ifstream::failbit | ifstream::badbit);
ifs.open(file);
while(ifs >> word) {
if(word == "foo") return true;
}
return false;
}
int main(int argc, char **argv)
{
try {
bool r = f(argv[1]);
cout << "f returned " << r << endl;
} catch(...) {
cerr << "exception" << endl;
}
}
But it doesn't work, because basic fstream reading using operator>> is evidently one of the operations for which EOF sets the bad or the fail bit. If the file exists and does not contain "foo" the function does not return false as desired, but rather throws an exception.
The std::ios_base::failbit flag is also set when there's an attempted extraction when the file has reached the end, something which the behavior of the stream's boolean operator allows. You should set up an extra try-catch block in f() and rethrow the exception if it doesn't correspond with the end of file condition:
std::ifstream ifs;
std::string word;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
ifs.open(file);
while (ifs >> word) {
if (word == "foo") return true;
}
}
catch (std::ios_base::failure&) {
if (!ifs.eof())
throw;
}
return false;
If the goal is to throw an exception only in case of a problem when opening the file, why not write:
bool f(const char *file)
{
ifstream ifs;
string word;
ifs.open(file);
if (ifs.fail()) // throw only when needed
throw std::exception("Cannot open file !"); // more accurate exception
while (ifs >> word) {
if (word == "foo") return true;
}
return false;
}
You could of course set :
ifs.exceptions(ifstream::badbit);
before or after the the open, to throw an exception in case something really bad would happen during the reading.
basic_ios::operator bool() checks fail(), not !good(). Your loop tries to read one more word after EOF is reached. operator>>(stream&, string&) sets failbit if no characters were extracted. That's why you always exit with an exception.
It's hard to avoid that though. The stream reaches EOF state not when the last character is read, but when an attempt is made to read past the last character. If that happens in the middle of a word, then failbit is not set. If it happens in the beginning (e.g. if the input has trailing whitespace), then failbit is set. You can't really reliably end up in eof() && !fail() state.
I'm trying to use an overloaded ">>" to scan input from a file.
The problem is, I have no idea how to deal with end of file.
In this case, my file is composed of a number, followed by several chars
Ex:
9rl
8d
6ff
istream &operator>>(istream &is, Move &move)
{
char c;
int i = 0;
c = is.get();
if (!isalnum(c))
return;
move.setNum(c); // I convert the char to an int, but I'l edit it out
while ( (c = is.get()) != '\n')
{
move.setDirection(i, c); //sets character c into in array at index i
i++;
} // while chars are not newline
return is;
} // operator >>
The test for the character being alpha numeric worked when I had this as a regular function, but doesn't work here as it expects an input stream to be returned. I've tried returning NULL as well. Suggestions?
EDIT: this is being called in a while loop, So i'm trying to figure out some way to have this trigger some flag so that I can break out of the loop. In my previous function, I had this return a boolean, returning true if successful or false if the character was not alphanumeric
Return is. Callers should check the stream for errors.
Be sure to set error bits as appropriate:
std::istream &operator>>(std::istream &is, Move &move)
{
char c;
int i = 0;
c = is.get();
if (is.eof())
return is;
else if (c < '0' || c > '9') {
is.setstate(std::ios::badbit);
return is;
}
else
move.setNum(c-'0');
while ( (c = is.get()) != '\n' && is)
move.setDirection(i++, c);
if (c != '\n')
is.setstate(std::ios::badbit);
return is;
}
Use it as in the following:
int main(int argc, char **argv)
{
std::stringstream s;
s << "9rl\n"
<< "8d\n"
<< "6ff\n";
s.seekg(0);
Move m;
while (s >> m)
std::cout << m;
if (s.bad())
std::cerr << argv[0] << ": extraction failed\n";
return 0;
}
Notice that the code uses the instance m only after successful extraction.
You can set the flags of the stream to a state such as ios::bad or ios::fail using ios::setstate. This will allow the caller to test the stream or in the case that exceptions are enabled for the stream, an exception will be raised.
You also fail to check the state of your stream. The C++ FAQ lite has a great section explaining this. To clarify this I have added the code snippet below.
c = is.get();
// the stream has not been tested to see if it read into c correctly
if (!isalnum(c))
return;