如何创建我的单例const的实例?

时间:2009-07-19 19:40:50

标签: c++ singleton const logging

我正在尝试为Ogre(一个开源3D引擎)的标准日志记录类创建一个包装器。我希望它具有与std::cerr相同的语法,并且在Linux上运行时也输出到cerr。这就是我所拥有的:

#ifndef _LOGGER_H_
#define _LOGGER_H_

#ifndef _XSTRING_
    #include <xstring>
#endif

#ifndef __LogManager_H__
    #include "OgreLogManager.h"
#endif

class Logger
{

public:

    static Logger* m_Instance;
    static Logger* getInstance() { return m_Instance; }
    static const Logger& getInstanceConst() { return *m_Instance; }

    Logger& operator << (const std::string& a_Message)
    {
        m_Log.append(a_Message);
        _CheckNewLine();
        return *m_Instance;
    }

    Logger& operator << (const char* a_Message)
    {
    m_Log += a_Message;
    _CheckNewLine();
    return *m_Instance;
}

private:

    std::string m_Log;

    Logger() 
    {
        m_Log = "";
    }

    void _CheckNewLine()
    {
        if (m_Log.at(m_Log.size() - 1) == '\n')
        {   
            Ogre::LogManager::getSingleton().logMessage(m_Log);

#if OGRE_PLATFORM != PLATFORM_WIN32 && OGRE_PLATFORM != OGRE_PLATFORM_WIN32

            std::cerr << m_Log;

#endif

            m_Log.clear();
        }
    }
};

#endif

现在,这工作正常,这个单例在.cpp:

中实例化
#include "logger.h"

Logger* Logger::m_Instance = new Logger(); 

当我想在多个标题中使用单例时出现问题。我在game3d.h中实例化它,几乎所有的标题都包含在这里:

Logger awesomelogger = Logger::getInstance();

不幸的是,这会导致尝试重新声明awesomelogger的标头出现多个错误。

我想让它成为一个const,这会让它消失,但这会引入新的错误。这就是我试过的:

friend Logger& operator << (const Logger& a_Logger, const std::string& a_Message)
{
    a_Logger.m_Log.append(a_Message);
    a_Logger._CheckNewLine();
    return *m_Instance;
}

我的问题是:我怎样才能使这个类的实例保持不变?或者如何重写这个类但仍然可以awesomelogger << "output" << s_Stuff << "\n";

6 个答案:

答案 0 :(得分:1)

与您的问题无关,但请注意,_LOGGER_H___LogManager_H__等名称在C ++中保留 - 您不能在自己的代码中使用它们。如果您不了解名称开头的下划线规则(或任何地方的双下划线),请不要使用它们。

现在,关于你的问题,记录器显然不是常量。提供对单身人士访问的经典方法是对此的一些变化:

static Logger* getInstance() { 
    static Logger logger;
    return & logger; 
}

答案 1 :(得分:1)

您的get_instance方法返回Logger *而不是Logger。

答案 2 :(得分:0)

创建一个指向 const 对象的 const 指针。

static const Logger * const m_Instance;

而不是

static Logger* m_Instance;

你也需要在课堂上进行很多相应的修正。

答案 3 :(得分:0)

一般来说,您的Logger“m_Instance”实例应该是私有的。你的函数“GetLogger()”应检查“m_Instance”是否尚未实例化(如果没有实例化),则返回m_Instance。

答案 4 :(得分:0)

经典的singelton模式如下所示:

#ifndef  THORS_ANVIL_MY_LOGGER_H
#define  THORS_ANVIL_MY_LOGGER_H

class MyLogger
{
  private:
   // Private Constructor
    MyLogger();
   // Stop the compiler generating methods of copy the object
    MyLogger(MyLogger const& copy);           // Not Implemented.
    MyLogger& operator=(MyLogger const& copy); // Not Implemented

  public:
    static MyLogger& getInstance()
    {
        // The only instance
        // Guaranteed to be lazy initialized
        // Guaranteed that it will be destroyed correctly
        static MyLogger instance;
        return instance;
    }
    template<typename T>
    MyLogger& operator<<(T const& data)
    {
          // LOG
          return *this;
    }
};

// continued below.

现在我们已经有了基本的模式。您需要看起来像全局变量才能访问它。最简单的方法是作弊而不是全局,但使用本地参考。

因此,在头文件中与Logger类定义一起添加以下内容。

namespace
{
    MyLogger&   logger = MyLogger::getInstance();
}
#endif

这在每个包含标头的编译单元中声明一个文件局部变量。 这已被初始化为引用作为singelton的记录器的实例。因为您需要在使用之前包含该文件,所以在任何使用之前总是会声明它,因此保证以正确的顺序初始化。

在主文件中:

#include "MyLogger.h"
int main()
{
    logger << "Plop";
}

答案 5 :(得分:0)

听起来是这样的:

  

当我想在多个标题中使用单例时出现问题。我在game3d.h中实例化它,几乎所有的标题都包含在这里:

 Logger awesomelogger = Logger::getInstance();

您正在每个包含game3d.h的模块中创建awesomelogger的新实例,并且由于此声明具有外部链接,因此这些名称将在链接时发生冲突。

有关C ++链接规则的说明,请参阅Linkage in Names with File Scope

更好的解决方案是无需创建awesomelogger变量,只需在需要的地方直接致电Logger::getInstance()