我怎样才能创建我的单例常量的实例?

发布于 2024-07-27 20:29:55 字数 1947 浏览 7 评论 0原文

我正在尝试为 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 的标头的多个错误。

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

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 << “输出”<< s_Stuff <<; “\n”;

I'm trying to make a wrapper for Ogre (an open source 3D engine) 's standard logging class. I want it to have the same syntax as std::cerr, and also output to cerr when running on Linux. Here's what I have:

#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

Now, this works fine, and this singleton is instanced in a .cpp:

#include "logger.h"

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

The problem comes when I want to use the singleton in multiple headers. I instantiate it in game3d.h, which is included by pretty much all the headers like this:

Logger awesomelogger = Logger::getInstance();

Unfortunately, this gives multiple errors about headers trying to redeclare awesomelogger.

I want to make it a const, which would make that go away, but that introduces new errors. This is what I tried:

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;
}

My question is: how can I make an instance of this class constant OR how can I rewrite this class but still be able to do awesomelogger << "output" << s_Stuff << "\n";

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

有木有妳兜一样 2024-08-03 20:29:55

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

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

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

Not to do with your question, but ote that names such as _LOGGER_H_ and __LogManager_H__ are reserverd in C++ - you are not allowed to use them in your own code. If you don't understand the rules regarding underscores at the start of names (or double underscores anywhere), then don't use them.

Now, regarding your question, a logger obviously isn't const. The classic way to provide access to a singleton is some variation on this:

static Logger* getInstance() { 
    static Logger logger;
    return & logger; 
}
捶死心动 2024-08-03 20:29:55

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

Your get_instance method returns Logger* not Logger.

倾城°AllureLove 2024-08-03 20:29:55

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

static const Logger * const m_Instance;

而不是

static Logger* m_Instance;

你在课堂上也需要很多相应的更正。

make a const pointer to a const object.

static const Logger * const m_Instance;

instead of

static Logger* m_Instance;

You'll need a lot of respective corrections in the class too.

清风夜微凉 2024-08-03 20:29:55

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

Generally speaking too, your instance of Logger "m_Instance" should be private. And your function "GetLogger()" should check if "m_Instance" has not been instantiated (if not instantiate it) then return m_Instance.

陌伤ぢ 2024-08-03 20:29:55

经典的辛格尔顿模式看起来像这样:

#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

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

在主文件中:

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

The classic singelton pattern looks like this:

#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.

Now we have the basic pattern out the way. You need what looks like a global variable to access it. The simplest way is to cheat and not have a global, but use a local reference.

So in the header file along with your Logger class definition add the following.

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

This declares a file local variable in every compilation unit that includes the header.
That has been initialized to refer to instance of the logger that is a singelton. Because you need to include the file before you can use it will always be declared before any usage and thus guranteed to be initialized in the correct order.

In main file:

#include "MyLogger.h"
int main()
{
    logger << "Plop";
}
猫卆 2024-08-03 20:29:55

由此听来:

当我想在多个标头中使用单例时,问题就出现了。 我在 game3d.h 中实例化它,几乎所有标头都包含该文件,如下所示:

 Logger awesomelogger = Logger::getInstance();

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

请参阅名称与文件范围的链接了解C++ 链接规则的解释。

更好的解决方案是无需创建 awesomelogger 变量,只需在需要的地方直接调用 Logger::getInstance() 即可。

It sounds from this:

The problem comes when I want to use the singleton in multiple headers. I instantiate it in game3d.h, which is included by pretty much all the headers like this:

 Logger awesomelogger = Logger::getInstance();

That you are creating a new instance of awesomelogger in every module that includes game3d.h and since this declaration has external linkage, these names will collide at link time.

See Linkage in Names with File Scope for an explanation of C++ linkage rules.

A better solution is to dispense with creating the awesomelogger variable and just call Logger::getInstance() directly wherever you need it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文