The Singleton pattern
Static class singleton
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
// Definition of a singleton logger class, implemented with static methods.
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Logs a single message at the given log level
static void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
static void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
// Closes the log file
static void teardown();
protected:
static void init();
static const char* const kLogFileName;
static bool sInitialized;
static std::ofstream sOutputStream;
private:
Logger() {}
};
这个方法的实现很直接。 sInitialized 静态成员在每次logging调用都需要检查。 需要显示调用teardown.
Access-Controller Singleton
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
// Definition of a true singleton logger class.
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Returns a reference to the singleton Logger object
static Logger& instance();
// Logs a single message at the given log level
void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
protected:
// Static variable for the one-and-only instance
static Logger sInstance;
// Constant for the file namename
static const char* const kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
private:
Logger();
virtual ~Logger();
};
// Implementation of a singleton logger class.
#include <stdexcept>
#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<string>& inMessages, const string& inLogLevel)
{
for (size_t i = 0; i < inMessages.size(); i++) {
log(inMessages[i], inLogLevel);
}
}
文件static依赖性问题。一些代码会获取sigleton,在它被构建之前,这会导致没有定义的行为很难追踪。第二个问题是销毁不是你想要的顺序。
Logger& Logger::instance()
{
static Logger sInstance;
return sInstance;
}
Singletions and Multithreading
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <mutex>
// Definition of a multithread safe singleton logger class
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Returns a reference to the singleton Logger object
static Logger& instance();
// Logs a single message at the given log level
void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
protected:
// Static variable for the one-and-only instance
static Logger* pInstance;
// Constant for the filename
static const char* const kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
// Embedded class to make sure the single Logger
// instance gets deleted on program shutdown.
friend class Cleanup;
class Cleanup
{
public:
~Cleanup();
};
// Logs message. The thread should own a lock on sMutex
// before calling this function.
void logHelper(const std::string& inMessage,
const std::string& inLogLevel);
private:
Logger();
virtual ~Logger();
Logger(const Logger&);
Logger& operator=(const Logger&);
static std::mutex sMutex;
};
// Implementation of a multithread safe singleton logger class
#include <stdexcept>
#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";
Logger* Logger::pInstance = nullptr;
mutex Logger::sMutex;
Logger& Logger::instance()
{
static Cleanup cleanup;
lock_guard<mutex> guard(sMutex);
if (pInstance == nullptr)
pInstance = new Logger();
return *pInstance;
}
Logger::Cleanup::~Cleanup()
{
lock_guard<mutex> guard(Logger::sMutex);
delete Logger::pInstance;
Logger::pInstance = nullptr;
}
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)
{
lock_guard<mutex> guard(sMutex);
logHelper(inMessage, inLogLevel);
}
void Logger::log(const vector<string>& inMessages, const string& inLogLevel)
{
lock_guard<mutex> guard(sMutex);
for (size_t i = 0; i < inMessages.size(); i++) {
logHelper(inMessages[i], inLogLevel);
}
}
void Logger::logHelper(const std::string& inMessage, const std::string& inLogLevel)
{
mOutputStream << inLogLevel << ": " << inMessage << endl;
}
Cleanup的作用是Logger实例每次都被正确删除。 Cleanup的静态实例在instance()方法第一次被调用时。当程序终止,C++运行时环境会销毁静态Cleanup实例。