Question

In my code, I want to identify some properties about the contents of a file, before deciding how to read the file. (That is, I search for a keyword, if found, it's going to be read with foo(std::ifstream&), else with bar(std::ifstream&)).

I implemented the method that searches for the keyword as

bool containsKeyword(std::ifstream& file, const char* keyword)
{
    for ( std::string line; std::getline(file, line); )
    {
        if ( line == keyword )
        {
            return true;
        }
    }
    return false;
}

This modifies the position of the file stream (either the end, if the keyword isn't found, or the position of the keyword). However I want that the position is reset after the search. This can be done with a ScopeGuard:

class FilePositionScopeGuard
{
   private:
      std::ifstream& file;
      using FilePosition = decltype(std::declval<std::ifstream>().tellg());
      FilePosition initial_position;
   public:
      FilePositionScopeGuard(std::ifstream& file_)
      :
         file(file_),
         initial_position(file.tellg())
      {
      }
      ~FilePositionScopeGuard()
      {
         file.clear();
         file.seekg(initial_position);
      }
};

Now we add this to the method:

bool containsKeyword(std::ifstream& file, const char* keyword)
{
    FilePositionScopeGuard guard(file);
    for ( std::string line; std::getline(file, line); )
    {
        ...

That's nice, because with exactly one additional line in the method, we get the behaviour of not modifying the std::ifstream no matter how the method is exited (one of the returns or an exception).

However, the method bool containsKeyword(std::ifstream&, const char*); does not express the constness. How can I adjust my method to express (at the level of the interface) that the method will not alter the current state?

Was it helpful?

Solution

You could change the signature to take a position-guarded file:

bool containsKeyword(const FilePositionScopeGuard &, const char *);

This allows the caller to pass an ifstream per the current signature (constructing a temporary guard for that operation), or to make their own guard and use it for several operations.

You'll need to make the ifstream member publicly accessible.

OTHER TIPS

Do it with the text comment // the method does read from file but resets the read pointer.

Do not expect a user of the API to be a monkey at keyboard. Specifically don't mark ifstream argument as const while casting constancy out inside the method. It does make difference in a multithreaded program.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top