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实例。

results matching ""

    No results matching ""