c++singletonfile-handlingofstream

How to handle ofstream object in case of application crash


I've a singleton logger class which will be used to write data into a single file and I'm just wondering how to handle the ofstream object in case of application crash.

#ifndef LOG_ERROR_H_
#define LOG_ERROR_H_

#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <fstream>
#include <memory>

namespace batch
{

  class ErrorLogger
  {

  public:
    ErrorLogger(const ErrorLogger &) = delete; 

    static ErrorLogger& Instance(std::string filename_)
    {
      static ErrorLogger error_instance(filename_);
      return error_instance;
    }
    

    void WriteLine(std::string content)
    {
      try
      {
        std::lock_guard<std::mutex> lk(error_stream_mutex);
        error_stream << content << std::endl;
      }
      catch(std::runtime_error const& e)
      {
        //cout
      }
    }

    ~ErrorLogger()
    {
      error_stream.close(); //Destructor is not getting called, should I explicitly call it?
    }

  private:
    std::ofstream error_stream;
    std::mutex error_stream_mutex;

    ErrorLogger(std::string filename) 
    {
        error_stream.open(filename);

        if (error_stream.fail())
        {
          throw std::iostream::failure("Cannot open file: " + filename);
        }
    }
  };
}

#endif

What I tried is instead of keeping the ofstream object open always, instantiate once and then open, close during writing but let's assume a scenario where I get the instance and the ofstream object is initialized and before calling WriteLine(), the application crashed then how should I handle the ofstream object?  

ErrorLogger(std::string filename) 
{
    error_stream(filename);
    if (error_stream.fail())
    {
        throw std::iostream::failure("Cannot open file: " + filename);
    }
}
void WriteLine(std::string content)
{
    try
    {
    error_stream.open(filename);
    if (error_stream.fail())
    {
        throw std::iostream::failure("Cannot open file: " + filename);
    }
    std::lock_guard<std::mutex> lk(error_stream_mutex);
    error_stream << content << std::endl;
    error_stream.close();
    }
    catch(std::runtime_error const& e)
    {
    //cout
    }
}    

So the question is how to properly handle error_stream (in a positive scenario as well as application crash scenario) i.e when should I close it, right now it is not getting closed.


Solution

  • If the application crashes, the operating system will close all files that were held open by your process, so you do not need to do anything about that scenario. (Not to mention that you can't really do anything.)

    While the application has not crashed (yet) you can keep flushing the file using std::flush (see https://en.cppreference.com/w/cpp/io/manip/flush) instead of closing it and then re-opening it; it is bound to perform better.