Search code examples
c++ifstream

Why does std::ifstream does not update if defined globally


I'm trying to write a simple tail program in C++. I've tried the example from this solution and it works like a charm.

Then, I tried to make the ifstream as global. Now the code does not work anymore and nothing is showed if I edit the file.

Why this behaviour? I read the manual of ifstream::open and I don't see any kind of error but the code does not work:

Opens the file identified by argument filename, associating it with the stream object, so that input/output operations are performed on its content. Argument mode specifies the opening mode.

Here is the non-working code:

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int find_last_linefeed(ifstream &infile) {
  infile.seekg(0,ios::end);
  int filesize = infile.tellg();
  for(int n=1;n<filesize;n++) {
    infile.seekg(filesize-n-1,ios::beg);
    char c;
    infile.get(c);
    if(c == 0x0A) return infile.tellg();
  }
}

ifstream infile;

int main() {
  int last_position=-1;
  for(;;) {
    infile.open("/Users/alberto/tmp/test");

    int position = find_last_linefeed(infile);
    if(position > last_position) {
      infile.seekg(position,ios::beg);
      string in;
      infile >> in;
      cout << in << endl;
    }
    last_position=position;
    sleep(1);
  }
}

Here is the working code:

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int find_last_linefeed(ifstream &infile) {
  infile.seekg(0,ios::end);
  int filesize = infile.tellg();
  for(int n=1;n<filesize;n++) {
    infile.seekg(filesize-n-1,ios::beg);
    char c;
    infile.get(c);
    if(c == 0x0A) return infile.tellg();
  }
}


int main() {
  int last_position=-1;
  for(;;) {

    ifstream infile;

    infile.open("/Users/alberto/tmp/test");

    int position = find_last_linefeed(infile);
    if(position > last_position) {
      infile.seekg(position,ios::beg);
      string in;
      infile >> in;
      cout << in << endl;
    }
    last_position=position;
    sleep(1);
  }
}

Solution

  • Since you open inside the loop, the stream will enter an error state on the second iteration, and keep failing after that.

    Move

    infile.open("/Users/alberto/tmp/test");
    

    outside the loop, or define infile like this and don't use open at all:

    ifstream infile("/Users/alberto/tmp/test");
    

    The best alternative is to not use a global variable at all, as there's no reason for it here.

    Also, find_last_linefeed fails to return anything if the file doesn't contain a linefeed, which is undefined.

    —-

    Regarding ifstream::open, from the standard (27.9.1.9):

    Calls rdbuf()->open(s, mode | ios_base::in). If that function does not return a null pointer calls clear(), otherwise calls setstate(failbit)

    and basic_filebuf::open (27.9.1.4):

    If is_open() != false, returns a null pointer