What does operator > and < mean when going with std::cout? [duplicate] - c++

I was trying a test program on failures of opening a file using ifstream. The code is below :-
#include <iostream>
#include <fstream>
#include <type_traits>
using namespace std;
int main()
{
ifstream ifs ("wrong_filename.txt");
cout << boolalpha;
cout << is_pointer<decltype(ifs)>::value <<"\n";
cout << (ifs==nullptr);
return 0;
}
Output is :-
false
true
If ifs is not a pointer, then how does it equal to nullptr?

Until C++11, C++ streams are implicitly convertible to void*. The result will be NULL if the stream is not in an errorless state and something else if it is. So ifs == NULL (should not work with nullptr, see below) will find and use that conversion, and since your filename was wrong, the comparison will yield true.
In C++11, this was changed to an explicit conversion to bool, with false indicating an error and true a good stream, because the void* conversion allowed too much nonsensical code, such as your example. Indeed, a current compiler in C++11 or C++14 mode will reject your snippet, live. Since your code is obviously at least C++11, your compiler is non-conforming by accepting it.
Those conversions allow and are intended for error checks like this:
if ( !(ifs >> data) )
std::cout << "Reading data failed.";
or, analogous to your example:
std::ifstream ifs ("wrong_filename.txt");
if (!ifs)
std::cout << "Could not open file.";
Fun fact of the day: You can also use this to cleanly loop over a file, e.g.:
for (std::string line; std::getline(ifs, line);) {
// Process line
}

Related

Invalid Operands to binary expression after switching from g++ to clang++ Error occurs in assert [duplicate]

I was trying a test program on failures of opening a file using ifstream. The code is below :-
#include <iostream>
#include <fstream>
#include <type_traits>
using namespace std;
int main()
{
ifstream ifs ("wrong_filename.txt");
cout << boolalpha;
cout << is_pointer<decltype(ifs)>::value <<"\n";
cout << (ifs==nullptr);
return 0;
}
Output is :-
false
true
If ifs is not a pointer, then how does it equal to nullptr?
Until C++11, C++ streams are implicitly convertible to void*. The result will be NULL if the stream is not in an errorless state and something else if it is. So ifs == NULL (should not work with nullptr, see below) will find and use that conversion, and since your filename was wrong, the comparison will yield true.
In C++11, this was changed to an explicit conversion to bool, with false indicating an error and true a good stream, because the void* conversion allowed too much nonsensical code, such as your example. Indeed, a current compiler in C++11 or C++14 mode will reject your snippet, live. Since your code is obviously at least C++11, your compiler is non-conforming by accepting it.
Those conversions allow and are intended for error checks like this:
if ( !(ifs >> data) )
std::cout << "Reading data failed.";
or, analogous to your example:
std::ifstream ifs ("wrong_filename.txt");
if (!ifs)
std::cout << "Could not open file.";
Fun fact of the day: You can also use this to cleanly loop over a file, e.g.:
for (std::string line; std::getline(ifs, line);) {
// Process line
}

Redirecting std::cin directly to std::cout

An exercise about standard io asks me to:
Read input from the standard input and write it to the standard output.
A possible solution is:
#include<iostream>
#include<string>
using std::cin; using std::cout;
using std::string;
int main()
{
string word;
while (cin >> word)
cout << word;
return 0;
}
The string acts as a buffer in this example. If one tries to get rid of the buffer by doing something like this:
#include<iostream>
using std::cin; using std::cout;
int main()
{
while (cout << cin)
;
return 0;
}
the results are very different. When I run this code I get an interminable stream of
0x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d300x600d30
on the terminal.
Why this happens? Why do these programs behave differently?
cout << cin will not work the way you want it to. In C++11 and later, it won't even compile.
You are seeing an unfortunate side-effect of the (now obsolete) "safe bool" idiom.
Before C++11, a std::istream could be implicitly converted to a void* to emulate bool semantics. (Since C++11, explicit operator bool() const fills that role)
Therefore, the code:
while (cout << cin)
compiles in C++98 or C++03, because it can be implicitly converted to:
while (cout << static_cast<void*>(cin) )
This cast is allowed to produce any non-NULL void* when cin is not in an error state. In your case, it is producing the pointer 0x600d30.
In first solution, you extract a string from cin and reinject it in cout. But in the second way, compiler tries to convert cin into a value suitable for injection in cout.
Your implementation converted cin to a pointer and repeatedly printed it. Mine simply converted cin to a bool and repeadedly prints 1.
But beware, even your first version is not transparent to multiple spaces or tabs, and would probably not respect lines either. I would prefer:
#include<iostream>
#include <string>
int main()
{
std::string line;
while (std::getline(std::cin, line)) {
std::cout << line << std::endl;
}
return 0;
}

Why does stream insertion of an empty streambuf fail?

I was using the simple file-slurp and I decided to add some error checking. I was surprised that an empty file gives an error. This doesn't happen with every empty sequence either, "" works fine. I also verified that rdbuf() is returning a non-null pointer.
#include <iostream>
#include <sstream>
using namespace std;
int main(int, char**){
istringstream in(""); // Succeeds if non-empty
stringstream sstr;
if (sstr << in.rdbuf()) { // Succeeds if I replace in.rdbuf() with ""
cout << "Read Successful\n";
}else{
cout << "Read Failed\n";
}
}
It sets failbit because the standard requires it. (I feel foolish now. I thought I might have been doing something wrong.) Section 27.7.3.6.3.9 of the November 2014 Draft says:
If the function inserts no characters, it calls setstate(failbit) (which may throw ios_base::failure (27.5.5.4)).
Why the committee decided to make this behavior different from other sequence insertions (like char* and string) which do not consider insertion of nothing to be a failure is still a mystery. But I now know it is not a failure indicating misuse of the object.

Behavior of fstream as a bool and fstream.good() function

I recently used fstream for a homework assignment and I was wondering about how two things worked.
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char** argv) {
ifstream myFile;
myFile.open("fileone.txt");
int myInt = 0;
while (myFile.good()) { // What is the difference between myFile and myFile.good()?
if (!myFile.eof()){
myFile >> myInt;
cout << myInt << endl;
}
}
return 0;
}
This is a snippet of my actual code I am working on. In another post, someone said that if I used while(myFile) , it would automatically convert into a bool. What is the difference between using this and using the member function .good() of the ifstream class? I know that .good() breaks out of the while loop when I reach the end of the text file but how does using the stream name behave?
IOStream classes have 4 functions for assessing the stream state: good(), bad(), fail(), and eof(). Excluding good(), each function checks a single bit in the underlying stream state and returns whether or not the bit is on (are there errors?). good() in particular checks if all the bits are off (is the stream valid?). These are what they are for:
good(): The stream has not encountered an error.
bad(): The stream has encountered an error that effects the integrity of the stream (i.e memory allocation failure, no buffer, etc.)
fail(): Typically a recoverable error (formatting/parsing failure).
eof(): The end-of-file (EOF) character has been reached.
When performing I/O, it is integral that you check for errors in the stream while processing input. What novices typically don't know is that the only function that was meant to be used to check for valid input is fail(). All the other functions are useful in other cases but not for conditioning input.
Futhermore, novices also fail to realize that input must be performed before checking for errors. Doing otherwise allows an unchecked extraction, allowing the body of the loop to access the value that was not produced from a valid extraction.
Streams have a boolean operator that returns !fail(), this allows you to check the stream in an elegant way after performing input, like this:
while (myFile >> myInt) {
// ...
}
This is the best way to perform input. The extraction itself should be present within a conditional context so that the body of whatever its being used in is executed only if the extraction succeeded.
Read the manual.
The bool conversion is defined so that the following are the same:
if (stream) { ... }
if (!stream.fail()) { ... }
There is a difference between stream.good() and !stream.fail(): !fail is also true the end of file.
And one more big issue with your code: you should check if the read is successful before using the input. So this is really bad:
myFile >> myInt;
cout << myInt << endl
because you have not checked if you really succeeded to read an int into myInt.
TLDR:
Use this for reading ints from a file:
while (myFile >> myInt) {
cout << myInt << endl;
}
Reason: myFile >> myInt returns myFile so it will invoke the bool conversion which should be used as the loop condition.

Semantics of flags on basic_ios

I find myself repeatedly baffled by the rdstate() flags - good(), bad(), eof(), fail() - and how they are expressed in basic_ios::operator!, operator bool and operator void*.
Could somebody put me out of my misery and explain this so I never have to think twice again?
There are three flags that indicate error state:
badbit means something has gone very wrong with the stream. It might be a buffer error or an error in whatever is feeding data to the stream. If this flag is set, it's likely that you aren't going to be using the stream anymore.
failbit means that an extraction or a read from the stream failed (or a write or insertion for output streams) and you need to be aware of that failure.
eofbit means the input stream has reached its end and there is nothing left to read. Note that this is set only after you attempt to read from an input stream that has reached its end (that is, it is set when an error occurs because you try to read data that isn't there).
The failbit may also be set by many operations that reach EOF. For example, if there is only whitespace left remaining in the stream and you try to read an int, you will both reach EOF and you will fail to read the int, so both flags will be set.
The fail() function tests badbit || failbit.
The good() function tests !(badbit || failbit || eofbit). That is, a stream is good when none of the bits are set.
You can reset the flags by using the ios::clear() member function; this allows you to set any of the error flags; by default (with no argument), it clears all three flags.
Streams do not overload operator bool(); operator void*() is used to implement a somewhat broken version of the safe bool idiom. This operator overload returns null if badbit or failbit is set, and non-null otherwise. You can use this to support the idiom of testing the success of an extraction as the condition of a loop or other control flow statement:
if (std::cin >> x) {
// extraction succeeded
}
else {
// extraction failed
}
The operator!() overload is the opposite of the operator void*(); it returns true if the badbit or failbit is set and false otherwise. The operator!() overload is not really needed anymore; it dates back to before operator overloads were supported completely and consistently (see sbi's question "Why does std::basic_ios overload the unary logical negation operator?").
C++0x fixes the problem that causes us to have to use the safe bool idiom, so in C++0x the basic_ios base class template does overload operator bool() as an explicit conversion operator; this operator has the same semantics as the current operator void*().
In addition to James' answer, it's important to remember that these flags indicate results of operations, so won't be set unless you perform one.
A common error is to do this:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream file("main.cpp");
while (!file.eof()) // while the file isn't at eof...
{
std::string line;
std::getline(file, line); // ...read a line...
std::cout << "> " << line << std::endl; // and print it
}
}
The problem here is that eof() won't be set until after we try to get the last line, at which point the stream will say "nope, no more!" and set it. This means the "correct" way is:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream file("main.cpp");
for (;;)
{
std::string line;
std::getline(file, line); // read a line...
if (file.eof()) // ...and check if it we were at eof
break;
std::cout << "> " << line << std::endl;
}
}
This places the check in the correct location. This is very unruly though; luckily for us, the return value for std::getline is the stream, and the stream has a conversion operator that allows it to be tested in a boolean context, with the value of fail(), which includes eof(). So we can just write:
#include <fstream>
#include <iostream>
#include <string>
int main()
{
std::ifstream file("main.cpp");
std::string line;
while (std::getline(file, line)) // get line, test if it was eof
std::cout << "> " << line << std::endl;
}