The following code behaves differently when compiled with g++ and with VC++ (in VS 2008):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
int main(int argc, char *argv[]) {
ifstream infile;
char *str = newchar[1000];
for (int i = 0; i < 4; i++) {
infile.open(argv[1],ios::in);
if (!infile.is_open()) {
cerr<<"FoF"<<endl;
exit(1);
}
while(!infile.eof()) {
infile.getline(str,1000);
cout<<i<<" "<<str<<endl;
}
infile.close()
}
return 0;
}
It traverses the file 4 times using g++ while just once with VC++ and one needs to add infile.seekg(ios::beg); after open() to make it traverse the file multiple times using VC++.
Can anyone tell me if this is a know issue and why does this fundamental behavior vary across compilers?
Perhaps the standard doesn't define what to do with the get pointer if you call close() but reuse the stream. Or maybe one of them is non standards compliant in that regard. Either way, moving the stream to its proper scope would fix it. This is your code, with indentation and some spaces added for clarity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int main(int argc, char *argv[])
{
ifstream infile;
char *str = newchar[1000];
for (int i = 0; i < 4; i++) {
infile.open(argv[1],ios::in);
if (!infile.is_open()) {
cerr << "FoF" << endl;
exit(1);
}
while(!infile.eof()) {
infile.getline(str,1000);
cout << i << " " << str << endl;
}
infile.close(); // added a semicolon here
}
return 0;
}
Now try to run this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int main(int argc, char *argv[])
{
string str; // it's C++
for (int i = 0; i < 4; i++) {
ifstream infile(argv[1]);
if (!infile.is_open()) {
cerr << "FoF" << endl;
exit(1);
}
while(getline(infile, str)) {
cout << i << " " << str << endl;
}
}
return 0;
}
Notice that now you create a different ifstream object on every iteration, while allowing the destructor to flush the buffer and close the file for you.
@filipe: Thanks for the corrections and the explanation. I knew that creating different ifstream objects will fix the problem. I was inquisitive that having closed the stream, why doesn't open() reposition the pointer in VC++ while it does in g++ and whether such issues should often be cared for while porting code across compilers.
@PanGalactic: Edited to add code tags. The ifstream reference still doesn't make it clear if the same file stream object may be used to open another file should reposition the stream pointer or not?
I am uncertain if open() is meant to clear any flags on the stream or not. As a matter of course, If I reuse a stream I call clear() before hand (usually after close() )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
int main(int argc, char *argv[]) {
ifstream infile;
char *str = newchar[1000];
for (int i = 0; i < 4; i++) {
infile.open("C://test.txt",ios::in);
if (!infile.is_open()) {
cerr<<"FoF"<<endl;
exit(1);
}
while(!infile.eof()) {
infile.getline(str,1000);
cout<<i<<" "<<str<<endl;
}
infile.close();
infile.clear();
}
return 0;
}
C++ ('98 Standard) 27.8.1.13 part 3.
If open() fails, failbit is set. There's nothing about the stream state being changed beyond that.
So you need to call clear(). Surprisingly, Visual C++ is doing the right thing.
I have to say that in all my many many years of using C++, I have never called open on a file stream. It goes against the whole ethos of a stream in my view. I support open/close being removed from fstream.
+1 on removing open/close. RAII all the way. I also want decent exception semantics. Oh, and the constructor should take a friggin' std::string. (Grrr!!)