Archived

This topic is now archived and is closed to further replies.

Glak

flaw in istream::operator bool() ?

Recommended Posts

I think all three should work, I had a couple different versions too. My guess is that the stream isn''t properly converting to a bool. I''m using MSVC++ 6. The two that don''t work crash with an unhandled exception error, after loading in all the images.
  
Image i;
vector<Image> frame;
frame.reserve(20);

ifstream ifs("testImages.txt");

//this works perfectly

for(int c = 0; c<16; ++c)
{	ifs >> i;
	frame.push_back(i);
}

//this doesn''t

while(ifs>>i)
	frame.push_back(i);

//nor does this

copy
(
	istream_iterator<Image>(ifstream( "testImages.txt" )),
	istream_iterator<Image>(),
	back_inserter(frame)
);
  

Share this post


Link to post
Share on other sites
Iostreams don''t throw any exceptions unless you tell them to. My hunch is that the exception/error is in your istream& operator>> (istream&, image) function. Remember that ''ifs>>i'' executes fully before the while loop can terminate. If there is a problem with the 17th image (eg. it doesn''t exist) and your operator isn''t well equipped to deal with that, it''ll crash.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yeah I just thought of that a few hours later while trying to sleep (6am maybe?). I''m going to try turning the stream false by setting one of those bits if the string read in evaluates to "" or something like that.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
in my Image input operator the first thing I do is read in a string. How come when I''m out of strings to read it doesn''t evaluate to false like it should? So instead I am checking for length equally 0. Doesn''t that mean that they implemented the operator for string incorrectly? Afterall once you run out of strings it should be false, otherwise istream_iterators for strings would be useless right?

  
string s;
//this version doesn''t work

/* if(!(stream >> s))
return stream;*/


//this one does

stream>>s;
if(s.length()==0)
{
stream.setstate(ios::eofbit);
return stream;
}

Share this post


Link to post
Share on other sites
Firstly, make sure you have all the fixes from the Dinkumware site implemented. I don''t think they affect EOF checking, but they might.

I don''t see why it wouldn''t set the failbit as well as the eofbit. (As that is what it''s supposed to do when reading past the EOF.) I took a quick look at the library internals but it''s all a bit complicated for me. All I can say is: the >> operator for std::istreams and std::strings works for me. It terminates on EOF as expected (because it sets failbit as well as eofbit.)

Sample code that works on my computer. If it doesn''t work on yours, you have a bug:
  
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream infile("C:/autoexec.bat");
string str;
while (infile >> str)
{
cout << str;
}
return 1;
}

Note that I''m checking that the stream is true in the conditional, you''re checking if it''s false. I don''t think this should be a problem if everything is implemented properly, but there is a lot of operator overloading involved and it''s possible that this is part of the problem.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yeah that works. I also threw a double negation in the while and it still works so that isn''t the problem. That means the problem has to be in my code but I don''t think I''m doing anything out of the ordinary. Here''s what I have:
  
istream& operator>> (istream& stream, Image& i)
{
string s;
/* if(!(stream >> s))
return stream;*/

stream>>s;

if(s.length()==0)
{
stream.setstate(ios::eofbit);
return stream;
}

//the rest, nothing more is read in

return stream;
}
//here is the code that calls it

Image i;
ifstream ifs("testImages.txt");

while(ifs>>i)
frame.push_back(i);



and here is the file:
circles.ttll
circles.ttlr
circles.ttrl
circles.ttrr
circles.tbll
circles.tblr
circles.tbrl
circles.tbrr
circles.btll
circles.btlr
circles.btrl
circles.btrr
circles.bbll
circles.bblr
circles.bbrl
circles.bbrr

I tried it with the cursor ending after the final ''r'' and with it on the next line, there is no difference. I thought that perhaps it might be reading in a 0 length string (which would crash it) but then in that sample program of yours I changed the print line to cout << str + "fgdfg" << endl; so if there was a 0 length string it would show up but that didn''t happen.

Share this post


Link to post
Share on other sites
Ok, I''m at a loss to see what the problem could be.

I can confirm that this snippet, modified from my above example:
  
ifstream infile("C:/circles.txt");
string str;
while (infile >> str)
{
cout << str << " / ";
}

... reads in that list of strings you posted just fine. So, it''s not the file, and there''s not a problem with the i(f)stream >> string operator. By the way, a zero length string should be perfectly acceptable. This means that you shouldn''t need to check for it to see if the stream''s done. You certainly shouldn''t have to set the eofbit yourself when using the standard extractor operators.

I can only suggest that you step into the code and see exactly where the problem is arising.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
ok I think I know what''s wrong. I decided to see what would happen if I commented out the line where I set eof. It shouldn''t crash (oh and the crash is because I use find to get the index of the ''.'' so I can break the string into texture name and the letters at the end that that say what part of the texture to use) but it should make an Image that doesn''t have any of its values set. Then after the place where I read in the Images I checked the length of the vector and it was 16. At first I was confused because I thought that there should be a 17 malformed Image. However there wasn''t, and without me doing anything the while loop terminated at the correct time.

Now though I think I see what was wrong. The conditional in the while is only going to be false when I''ve read in bad string, however the input operator doesn''t know that so it will continue to work unless you check and make it return. If it will crash as a result of bad input you have to make sure to check for bad input and return to avoid the crash or whatever other bad stuff might happen. One thing that seems strange is that I am able to call length() on a string with a value of null, I always assumed calling methods on null wasn''t allowed. So I guess the lesson that I learned is to put: if(!stream) return stream; in all your input operators after reading in whatever you need. Thanks a lot.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
One thing that seems strange is that I am able to call length() on a string with a value of null, I always assumed calling methods on null wasn''t allowed.

The string itself isn''t null just because it couldn''t read anything in. It is a valid zero-length string object. You can work with these just fine, so long as you don''t try accessing a character in it that doesn''t exist. (In this case, even character zero doesn''t exist.)
quote:
So I guess the lesson that I learned is to put: if(!stream) return stream; in all your input operators after reading in whatever you need.

Not really... you should put "return stream;" no matter whether it''s false or true. You pass back the state of the stream regardless of what has happened to it, so in general you only need one return statement at the end of the function.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
yeah it isn''t a pointer so it can''t be null, but the debugger had all zeros next to the name when it should have had something else, but I guess it doesn''t really matter. I do think that the return is neccessary, if I take it out I get a crash when I to do stuff with worthless input. Once I realize that the stream is used up that means that whatever code it is executing is pointless and possibly harmful, so it is best to return there, after all the object won''t be used anyway.

Share this post


Link to post
Share on other sites
All I''m saying, is that instead of

if (!stream)
return stream;
DoSomethingWithStream(stream);
return stream;


you could just do...

if (stream)
{
DoSomethingWithStream(stream);
}
return stream;

Less ambiguity, fewer paths out of the function...

Share this post


Link to post
Share on other sites