How does it do that??: C++ Stream object question

Started by
4 comments, last by fpsgamer 17 years, 8 months ago
A book I have says that to check if a stream object has had an error simply check the "return value of the entire stream object", for example: ofstream os; os.open("a.dat", ios::binary); if(!os){ //error } How can we do that simply checking the object name? Could someone outline a class with this functionality so I can see how it works. Thanks :)
Advertisement
Use a bool cast operator.

operator bool() const{  return this->isValid;}
std::basic_ios<>, one of the base classes of ofstream, defines two overloaded operators: operator! and operator void *. When you use !os, the compiler calls basic_ios<>::operator!(), which then returns if the bad bits are set. Similarly if you try to use os as a boolean value, it calls operator void *(), which returns non-null if the stream is good, and null if the stream is bad.
class Test{public:   Test():valid(true)   {   }   operator bool() const   {      return valid;   }   void toggleValid()   {       valid = !valid;   }private:   bool valid;};void func(){   Test test;   if( test )      std::cout << "test is good\n";   else      std::cout << "test is bad\n";   test.toggleValid();   if( test )      std::cout << "test is good\n";   else      std::cout << "test is bad\n";}

operator bool() can be changed to any type, like operator float().

Implicit casts shouold be avoided. They can be problematic in many cases, and not all make sense.

I prefer to use an explicit isValid() function, as it makes what happens clearer.
all the stream classes reveal a pointer

so if some error occurs then the pointer will be null

That's why you can check for erroes like that

You can check the state o a strem with this fucntions also.

good() Returns true if the stream is OK (goodbit is "set")
eof() Returns true if end-of-file was hit (eofbit is set)
fail() Returns true if an error has occurred (failbit or badbit is set)
bad() Returns true if a fatal error has occurred (badbit is set)

<code>

Stream State and Boolean Conditions

Two functions are defined for the use of streams in Boolean expressions (Table 13.5).

Table 13.5. Stream Operators for Boolean Expressions Member Function Meaning
operator void*() Returns whether the stream has not run into an error (corresponds to !fail())
operator !() Returns whether the stream has run into an error (corresponds to fail())

With operator void*(), streams can be tested in control structures in a short and idiomatic way for their current state:

// while the standard input stream is OK
while (std::cin) {
...
}
For the Boolean condition in a control structure, the type does not need a direct conversion to bool. Instead, a unique conversion to an integral type (such as int or char) or to a pointer type is sufficient. The conversion to void* is often used to read objects and test for success in the same expression:

if (std::cin >> x) {
// reading x wax successful
...
}
As discussed earlier, the expression

std::cin >> x
returns cin. So after x is read, the statement is

if (std::cin) {
...
}
Because cin is being used in the context of a condition, its operator void* is called, which returns whether the stream has run into an error.

A typical application of this technique is a loop that reads and processes objects:

// as long as obj can be read
while (std::cin >> obj) {
// process obj (in this case, simply output it)
std::cout << obj << std::endl;
}
This is C's classic filter framework for C++ objects. The loop is terminated if the failbit or badbit is set. This happens when an error occurred or at end-of-file (the attempt to read at end-of-file results in setting eofbit and failbit;). By default, operator >> skips leading whitespaces. This is normally exactly what is desired. However, if obj is of type char, whitespace is normally considered to be significant. In this case you can use the put() and get() member functions of streams (see page 611) or, even better, an istreambuf_iterator (see page 667) to implement an I/O filter.

With operator !, the inverse test can be performed. The operator is defined to return whether a stream has run into an error; that is, it returns true if failbit or badbit is set. It can be used like this:

if (! std::cin) {
// the stream cin is not OK
...
}
Like the implicit conversion to a Boolean value, this operator is often used to test for success in the same expression in which an object was read:

if (! (std::cin >> x)) {
// the read failed
...
}
Here, the expression

std::cin >> x
returns cin, to which operator ! is applied. The expression after ! must be placed within parentheses. This is due to the operator precedence rules: without the parentheses, operator ! would be evaluated first. In other words, the expression

! std::cin >> x
is equivalent to the expression

(!std::cin) >> x
This is probably not what is intended.

Although these operators are very convenient in Boolean expressions, one oddity has to be noted: Double "negation" does not yield the original object:

cin is a stream object of class istream.

!! cin is a Boolean value describing the state of cin.

As with other features of C++, it can be argued whether the use of the conversions to a Boolean value is good style. The use of member functions such as fail() normally yields a more readable program:

std::cin >> x;
if (std::cin.fail()) {
...
}

</code>
oooh. Overloading operator void* is completely new to me (overloading operator bool() didn't occur to me either)....

So that means if you overload void* you'd write something like:

operator void*() const{if(conditionIsTrue)return (void*)1;elsereturn (void*)0;}


[Edited by - fpsgamer on August 20, 2006 9:24:55 AM]

This topic is closed to new replies.

Advertisement