Первый: использование std::unique_ptr
не нужно:
void Log::LogMsg(std::string const& s) {
static Log L;
L.log(s);
}
Создает точно такую же ленивую семантику инициализации и очистки, не вводя весь синтаксический шум (и избыточный тест).
Теперь это не так ...
Ваш класс очень прост. Возможно, вы захотите создать немного более сложную версию, типичные требования для сообщений журнала:
- 1012 * Отметка времени *
- уровень
- файл
- линия
- функция
- имя процесса / идентификатор потока (при необходимости)
поверх самого сообщения.
Таким образом, вполне возможно иметь несколько объектов с разными параметрами:
// LogSink is a backend consuming preformatted messages
// there can be several different instances depending on where
// to send the data
class Logger {
public:
Logger(Level l, LogSink& ls);
void operator()(std::string const& message,
char const* function,
char const* file,
int line);
private:
Level _level;
LogSink& _sink;
};
А для удобства вы обычно заключаете доступ в макрос:
#define LOG(Logger_, Message_) \
Logger_( \
static_cast<std::ostringstream&>( \
std::ostringstream().flush() << Message_ \
).str(), \
__FUNCTION__, \
__FILE__, \
__LINE__ \
);
Теперь мы можем создать простой подробный регистратор:
Logger& Debug() {
static Logger logger(Level::Debug, Console);
return logger;
}
#ifdef NDEBUG
# define LOG_DEBUG(_) do {} while(0)
#else
# define LOG_DEBUG(Message_) LOG(Debug(), Message_)
#endif
И пользуйтесь им удобно:
int foo(int a, int b) {
int result = a + b;
LOG_DEBUG("a = " << a << ", b = " << b << " --> result = " << result)
return result;
}
Цель этой напыщенной речи? Не все, что является глобальным, должно быть уникальным . Уникальность синглетонов вообще бесполезна.
Примечание: если вас пугает бит магии с std::ostringstream
, это нормально, см. Этот вопрос