Expressing "read-only, no modification of position" for std::ifstream

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?

Answers


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.


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.


Need Your Help

setOnItemClickListener() not working on listView of Fragments

java android android-layout listview onitemclicklistener

I have some issues with handle click's on my ListView element witch contains customized ArrayAdapter of Fragments. There is no checkbox anywhere, only Button in Fragment is ImageButton and it alrea...

php: Using <form> tag to sum a new value to an existing value in php

php html mysql forms

I am creating a webpage that is similar to a points system. It consists of a table with name and points columns. The user inputs a number, which then adds that value to the existing number in the t...