Online Book Reader

Home Category

Professional C__ - Marc Gregoire [484]

By Root 1146 0
Data member for the output stream

std::ofstream mOutputStream;

private:

Logger();

virtual ~Logger();

};

Code snippet from SingletonLogger\Logger.h

One advantage of this approach is already apparent. Because an actual object will exist, the init() and teardown() methods present in the static solution can be omitted in favor of a constructor and destructor. This is a big win, because the previous solution required the client to explicitly call teardown() to close the file. Now that the logger is an object, the file can be closed when the object is destructed, which will happen when the program ends.

The implementation follows. Notice that the actual log() methods remain almost unchanged, except for the fact that they are no longer static, and that they no longer have to check if the logger has been initialized. The constructor and destructor are called automatically because the class contains an instance of itself as a static member. Because they are private, no external code can create or delete a Logger.

#include

#include "Logger.h"

using namespace std;

const string Logger::kLogLevelDebug = "DEBUG";

const string Logger::kLogLevelInfo = "INFO";

const string Logger::kLogLevelError = "ERROR";

const char* const Logger::kLogFileName = "log.out";

// The static instance will be constructed when the program starts and

// destructed when it ends.

Logger Logger::sInstance;

Logger& Logger::instance()

{

return sInstance;

}

Logger::~Logger()

{

mOutputStream.close();

}

Logger::Logger()

{

mOutputStream.open(kLogFileName, ios_base::app);

if (!mOutputStream.good()) {

throw runtime_error("Unable to initialize the Logger!");

}

}

void Logger::log(const string& inMessage, const string& inLogLevel)

{

mOutputStream << inLogLevel << ": " << inMessage << endl;

}

void Logger::log(const vector& inMessages, const string& inLogLevel)

{

for (size_t i = 0; i < inMessages.size(); i++) {

log(inMessages[i], inLogLevel);

}

}

Code snippet from SingletonLogger\Logger.cpp

Using a Singleton

The following two pieces of code display the usage of the two different versions of the Logger class:

Logger::log("test message", Logger::kLogLevelDebug);

vector items = {"item1", "item2"};

Logger::log(items, Logger::kLogLevelError);

Logger::teardown();

Code snippet from StaticLogger\TestStaticLogger.cpp

Logger::instance().log("test message", Logger::kLogLevelDebug);

vector items = {"item1", "item2"};

Logger::instance().log(items, Logger::kLogLevelError);

Code snippet from SingletonLogger\TestTrueSingletonLogger.cpp

Both programs have the same functionality. After executing, the file log.out should contain the following lines:

DEBUG: test message

ERROR: item1

ERROR: item2

Singletons and Multithreading

The implementation of the singleton pattern in the previous section has a few issues. The first problem has to do with file static dependencies. The C++ standard does not define the order of initialization of static variables across translation units. Because of this, it can happen that some code is accessing the singleton class before it has been constructed, which leads to undefined behavior that is difficult to track. A second problem is that destruction of static objects is not guaranteed to occur in the order that you desire.

These problems can be solved by moving the static instance into the instance() method as follows:

Logger& Logger::instance()

{

static Logger sInstance;

return sInstance;

}

However, this solution is not safe in a multithreaded scenario, because there can be a race condition between the two lines in the new instance() method. To fix this race condition, the following implementation uses a static pInstance pointer to the single instance of the class. This static pointer will be initialized within a thread-safe block of code using a mutex for thread synchronization. The copy constructor and assignment operator are declared as private. The reason for the Cleanup class is discussed later in this section.

#include

#include

Return Main Page Previous Page Next Page

®Online Book Reader