Some of you will recognize this routine from some help you've given me in the past. It's a general-purpose routine to performa formatted read of a number of elements from a text file.
template <class T> int getVector(ifstream & s,
const int32_t & nbrCells,
typename vector<T>::iterator iter)
{
int rc = 0;
union
{ int32_t temp;
uint32_t utemp;
} intBuffer;
for (int i = 0; i < nbrCells; i++)
{
if (s.flags() & ios::hex)
s >> intBuffer.utemp;
else
s >> intBuffer.temp;
if (s.good())
{
*iter++ = intBuffer.temp;
}
elseif (s.eof())
{
rc = 1;
cout << "getVector: encountered end of file." << endl;
}
elseif (s.fail())
{
rc = 1;
cout << "getVector: read fail." << endl;
}
}
return rc;
}
I've encountered a mildly unexpected problem with it. I have a data file that contains exactly 256 elements (the actual number isn't important). All of the elements are separated by line breaks, BUT the final element doesn't have a line break after it.
When I read all 256 in, the s.eof() returns true. All I want to use the eof() function for is to ensure that I've gotten all the data out of the file; that is, that I've fully populated my vector. Am I mis-using the eof() here, and/or is there a better way to perform that test?
There is a workaround for this problem: if I edit my input files and put an end of line after the last element, it seems to work OK. I'd prefer not to have to do this, though.
Thanks, PG. I can't quite simplify it that much, since not every function is going to read the entire file. But, I think I can still use your technique with the distance() function, can't I?
Also: is distance() a part of the standard STL? The only online reference to it I can find is for MS variants of C++. This code has to be portable.
OK, that's good news. But, I still need the check for good(), so I can update my vector. If I use bad(), it will return true on an EOF, right? Or, are you suggesting I just go ahead with the read, and check that I "got them all" at the end?
I got pulled off on another task for a couple of days. Here's what I've done with your suggestions; please tell me what you think:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int rc = 0;
typename vector<T>::iterator save = iter;
union
{ int32_t temp;
uint32_t utemp;
} intBuffer;
while (s.good() && (distance(save, iter) != nbrCells))
{
if (s.flags() & ios::hex)
s >> intBuffer.utemp;
else
s >> intBuffer.temp;
*iter++ = intBuffer.temp;
}
If I've done this right, this will read until 1) there's a problem with the input stream, or 2) I've gotten the number of items from the read the calling function requested.
It's broken. You call s>>intBuffer.temp and assign that data to the vector before checking if the stream is still good. The extract may have failed, leaving garbage data in the vector.
OK, I discovered a problem with this: the extraction will execute once more than necessary in some cases. I fixed it like this:
while ((distance(save, iter) != nbrCells) && (s >> utemp))
The question is, can I rely on this? Specifically, can I rely on the compiler (indeed, all compilers) to evaluate the expression on the left *before* evaluating/extracting as per the right?