C++ 在c+中记录时出错+;

C++ 在c+中记录时出错+;,c++,C++,我实现了一个非常简单的(错误)记录器类。看起来是这样的: #pragma once #include <string> extern const char* LOG_DEFAULT_TEXT = "<LOG>\n\n"; class Log { public: Log() : _logs(0), _log(LOG_DEFAULT_TEXT) {}; void add(const char *str, bool nl=true); void

我实现了一个非常简单的(错误)记录器类。看起来是这样的:

#pragma once

#include <string>

extern const char* LOG_DEFAULT_TEXT =  "<LOG>\n\n";

class Log
{
public:
    Log() : _logs(0), _log(LOG_DEFAULT_TEXT) {};

    void add(const char *str, bool nl=true);
    void clear();

    const char* get() const { return _log.c_str(); }
    int getNumLogs() const { return _logs; }


private:
    std::string _log;
    int _logs;
};
//Main.h
...

#include "Log.h"

class Main() {
public:
  ...

private:
  Log _log;
  ImportantObject1(&_log); //pass a pointer to _log
  ImportantObject2(&_log); //..same
};

这个解决方案似乎太笨拙了,所以我想问一下,对于我想要完成的事情,是否有不同的方法,即错误日志记录。

这是一种罕见的单例有意义的情况之一:

class Log
{
public:

    void add(const char *str, bool nl=true);
    void clear();

    const char* get() const { return _log.c_str(); }
    int getNumLogs() const { return _logs; }

    static Log& instance() {
         static Log theInstance;
         return theInstance;
    }
private:
    Log() : _logs(0), _log(LOG_DEFAULT_TEXT) {};

    std::string _log;
    int _logs;
};
这样,您就可以在其他地方使用它

 Log::instance().add("Blah Blah",true);

另一种解决需求的方法

在合适的
命名空间中使用函数,而不是使用单例。

Log.h:

namespace Log
{
   void add(const char *str, bool nl=true);
   void clear();

   const char* get();
   int getNumLogs();
}
Log.cpp:

namespace detail
{
   // This is almost same as the class from OP's post.
   struct LogImpl
   {
      LogImpl(std::string const& log) : _logs(0), _log(log) {};

      void add(const char *str, bool nl=true);
      void clear();

      const char* get() const { return _log.c_str(); }
      int getNumLogs() const { return _logs; }


      std::string _log;
      int _logs;
   };
}

namespace Log
{
   // This mimics the singleton implementation...
   // Create only one instance of LogImpl.

   static detail::LogImpl impl("<LOG>\n\n");

   void add(const char *str, bool nl)
   {
      impl.add(str, nl);
   }
   void clear()
   {
      impl.clear();
   }

   const char* get()
   {
      return impl.get();
   }
   int getNumLogs()
   {
      return impl.getNumLogs();
   }
}

namespace Log
{

   void add(const char *str, bool nl=true);
   void clear();

   const char* get();
   int getNumLogs();
}
而不是

Log::instance()->add(...);

从C继承的另一个常见模式是全局对象。全球化通常是不受欢迎的,因为它们是糟糕设计的征兆。但作为一名全球记录者是有意义的

这意味着类的标题应包含:

extern Log log;
和人民党

#include <log.h>
...
Log log;    // unique definition for the global Log
#包括
...
日志日志;//全局日志的唯一定义
然后在使用日志的任何模块中:

#include <log.h>
...
log.add(...);
#包括
...
log.add(…);
这里的警告是,将对日志进行静态初始化。和C++不总是很好的静态初始化顺序:否则,变量的初始化相对于变量的初始化是不确定的 在不同的转换单位中定义的变量。。唯一简单的方法是确保:

  • 日志构造不依赖于任何其他静态初始化变量,该变量需要另一个翻译单元中的构造函数阶段-它包括
    std::string
    ,但希望不是
    const char*
  • 全局变量在任何多线程开始之前使用一次

如果有疑问,使用πάντα建议的单态模式ῥεῖ

如果需要更灵活的方法,这就是模式。@Quentin对于像日志记录这样的简单用例来说,这听起来有点过度设计了。如果您返回一个局部变量作为引用,它将无法正常工作;)事实上,我从来没有真正理解过单身汉背后的想法,现在我明白了。我总是被告知关于它们的可怕消息:P@πάνταῥεῖ 以防万一:)在使用globals时必须指出一点:如果全局对象的构造顺序没有很好地定义,您可能会遇到麻烦。可能创建了另一个全局对象并尝试记录,但记录器不可用,系统在没有日志的情况下崩溃;)但是,单例最终会出现在依赖树中,等等。没有模式是完美的。如果您知道自己在做什么,那么全局对象既便宜又快捷。但如果你不这样做,那就是噩梦的开始!
#include <log.h>
...
log.add(...);