How can an object reference work as a boolean expression? - c++

I'm reading file by file stream in the C++ Standard Library:
std::ifstream infile(path.c_str());
if (!infile.is_open())
{
return -1;
}
std::string line;
while (std::getline(infile, line))
{
std::cout << line << std::endl;
}
This works. What impressed me is that std::getline actually returns an std::ifstream&; how can a reference to object work as a boolean expression? Second, if I write it this way:
while (NULL != std::getline(infile, line))
this also works. I don't get it why a reference here works like a pointer.

It's not the object reference: std::ifstream supports conversion to bool (it used to be void* before C++11), as you can see here: http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool.
It returns true (a non null pointer before C++11) unless the stream is in error or at EOF.

std::ifstream is convertible to boolean. Specifically, it's true if the stream is good, and false if the stream is bad or fail.

std::ifstream defines void * conversion operator. So you can compare the reference with a pointer and as a boolean condition.
Quoting about the return value of this conversion operator from cplusplus.com
Return Value: A null pointer if at least one of failbit or badbit is set. Some other
value otherwise

Related

testing an istream object

When I use an std::istream object (in the example below from cplusplus.com, an std::ifstream) in a test : "if (myistreamobject)", the object, which is automatically allocated in the stack is never null, right ?... in the example below, we are using the same test to check if all the bytes were read from the file... and that's really a strange code, I usually use that style when I'm dealing with pointers...
I want to know which mechanism is used in std::istream to return a value in tests, and what that value really means... (the success/failure of the last operation ??) is it an overloading of a bool cast (like the const char* operator cast in the MFC class CString) or it is another technique ?
Because the object is never null, so putting it in a test will always return true.
// read a file into memory
#include <iostream> // std::cout
#include <fstream> // std::ifstream
int main () {
std::ifstream is ("test.txt", std::ifstream::binary);
if (is) {
// get length of file:
is.seekg (0, is.end);
int length = is.tellg();
is.seekg (0, is.beg);
char * buffer = new char [length];
std::cout << "Reading " << length << " characters... ";
// read data as a block:
is.read (buffer,length);
if (is) // <== this is really odd
std::cout << "all characters read successfully.";
else
std::cout << "error: only " << is.gcount() << " could be read";
is.close();
// ...buffer contains the entire file...
delete[] buffer;
}
return 0;
}
if (expression)
tests it expression evaluates to true which is a boolean. It works for pointers because nullptr/NULL/0 evaluate to false, and everything else true. It works for integral values for the same reason.
For an object, it falls to operator bool(), see http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool.
Checks whether the stream has no errors.
1) Returns a null pointer if fail() returns true, otherwise returns a non-null pointer. This pointer is implicitly convertible to bool and may be used in boolean contexts.
2) Returns true if the stream has no errors and is ready for I/O operations. Specifically, returns !fail().
This operator makes it possible to use streams and functions that return references to streams as loop conditions, resulting in the idiomatic C++ input loops such as while(stream >> value) {...} or while(getline(stream, string)){...}.
Such loops execute the loop's body only if the input operation succeeded.
The
operator bool()
returns true if the stream has no errors, false otherwise.
The "no error" concept is something related with the previous operation done on the stream itself.
For example: after you invoke the constructor
std::ifstream is ("test.txt", std::ifstream::binary);
A internal status flag in the stream object is set. So when you invoke the operator bool you check whether the construction operation fails or not.
Moreover the method
is.read(...)
also set this internal status flag, as you can see in the reference:
Errors are signaled by modifying the internal state flags: eofbit, failbit, badbit.
So after the method call, if the stream reaches the EOF (end-of-file) the state bit is set, and the operator bool will return a positive value.
That means in that case when you test the stream with
if (is) { ... }
and the status bit is set, then the condition will be verified and the if-branch will be taken.
std::istream has operator declared right this:
explicit operator bool() const;
When you write
if(SomeStdIstremObject) { ... } really is calling if(SomeStdIstreamObject.operator bool()) not checking for non zero

Why does while(std::ifstream >> s) work?

I've used statements such as this quite a bit in my C++ programming:
std::string s;
std::ifstream in("my_input.txt");
if(!in) {
std::cerr << "File not opened" << std::endl;
exit(1);
}
while(in >> s) {
// Do something with s
}
What I want to know is, why does this work?
I looked at the return value of operator>>, and it's an istream object, not a boolean. How does an istream object somehow get interpreted as a bool value that can be put inside of if statements and while loops?
The base class std::basic_ios provides an operator bool() method that returns a boolean representing the validity of the stream. For example, if a read reached the end of file without grabbing any characters, then std::ios_base::failbit will be set in the stream. Then operator bool() will be invoked, returning !fail(), at which time extraction will stop because the condition is false.
A conditional expression represents an explicit boolean conversion, so this:
while (in >> s)
is equivalent to this
while (static_cast<bool>(in >> s))
which is equivalent to this
while ((in >> s).operator bool())
which is equivalent to
while (!(in >> s).fail())
std::basic_ios, from which the input and output streams inherit, has the conversion function operator bool (or operator void* prior to C++11 to get around the safe-bool problem, which is no longer an issue thanks to the explicit keyword).
See std::basic_ios::operator bool:
This operator makes it possible to use streams and functions that return references to streams as loop conditions, resulting in the idiomatic C++ input loops such as while(stream >> value) {...} or while(getline(stream, string)){...}. Such loops execute the loop's body only if the input operation succeeded.

istream (ostream) vs. bool

Here is a C++ code which reads as many words
from a given text file as possible until it meets EOF.
string text;
fstream inputStream;
inputStream.open("filename.txt");
while (inputStream >> text)
cout << text << endl;
inputStream.close();
My question is:
what procedure exactly is performed behind on converting the condition of the while loop (i.e., inputStream >> text) into a boolean values (i.e., true or false)?
My own answer for the question is:
To my understanding, inputStream >> text is supposed to return another (file) input stream. The stream seems to be NULL when EOF arrives. The NULL may be defined as 0, which is equivalent to false.
Does my answer make sense? Even if my answer does make sense, such conversion of InputStream to bool doesn't make me so comfortable. :)
what procedure exactly is performed behind on converting the condition of the while loop (i.e., inputStream >> text) into a boolean values (i.e., true or false)?
operator>> returns a reference to the stream.
In C++11 the reference is then converted to a bool by the stream's operator bool() function, which returns the equivalent of !fail().
In C++98 the same is achieved by using operator void*(), and the returned pointer is either NULL to indicate failure or a non-null pointer if fail() is false, which is then implicitly converted to a bool in the while evaluation.
I know that my answer has been perfectly answered by user657267. But I am adding one more example to understand the answer more easily.
// evaluating a stream
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
int main () {
std::ifstream is;
is.open ("test.txt");
if (is) { <===== Here, an example of converting ifstream into bool
// read file
}
else {
std::cerr << "Error opening 'test.txt'\n";
}
return 0;
}
Ref. http://www.cplusplus.com/reference/ios/ios/operator_bool/

istream::getline return type

What does the istream::getline method return?
I am asking because I have seen that to loop through a file, it should be done like this:
while ( file.getline( char*, int ) )
{
// handle input
}
What is being returned?
It returns a stream so that we can chain the operation.
But when you use an object in a boolean context the compiler looks for an conversion operator that can convert it into a type that can be used in the boolean context.
C++11
In this case stream has explicit operator bool() const. When called it checks the error flags. If either failbit or badbit are set then it returns false otherwise it returns true.
C++03
In this case stream has operator void*() const. As this results in a pointer it can be used in a boolean context. When called it checks the error flags. If either failbit or badbit are set then it returns NULL which is equivalent to FALSE otherwise it returns a pointer to self (or something else valid though you should not use this fact)).
Usage
So you can use a stream in any context that would require a boolean test:
if (stream >> x)
{
}
while(stream)
{
/* do Stuff */
}
Note: It is bad idea to test the stream on the outside and then read/write to it inside the body of the conditional/loop statement. This is because the act of reading may make the stream bad. It is usually better to do the read as part of the test.
while(std::getline(stream, line))
{
// The read worked and line is valid.
}
Look from reference. The istream returned from getline is converted to bool by implicit conversion to check success of operation. That conversion makes usage of if(mystream.getline(a,b)) into shorthand for if(!mystream.getline(a,b).fail()).
It returns the stream itself. The stream can convert (through void*) to bool indicating its state. In this example, your while loop will terminate when the stream's conversion to bool goes "false", which happens when your stream enters an error state. In your code, it's most likely to occur when there was an attempt to read past the end of the file. In short, it'll read as much as there is, and then stop.
The function returns a reference to the stream object itself, which can be used either to chain further read operations:
myStream.getline(...).getline(...);
or, because streams are implicitly convertible to void *s, in a loop or condition:
while (myStream.getline(...)) {
...
}
You can read more about this on the cplusplus.com website:
http://cplusplus.com/reference/iostream/istream/getline/
Everyone has told you what it is, now let me tell you, use the free form version
std::string line;
while(getline(file, line)) // assuming file is an instance of istream
{
//
}
Why this version? It should become immediately apparent - you pass in a std::string rather than some fixed size character buffer!

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;
}