使用智能指针实现对单例模式指针内存的管理,并采用模板编程做到一句宏定义就能调用方法
#ifndef _SINGLETON_H_
#define _SINGLETON_H_
#pragma once
#include <memory>
template <typename T>
class CSingleton
{
public:
static std::unique_ptr<T>& GetInstance()
{
if (!m_pInstance)
m_pInstance.reset(new T);
return m_pInstance;
}
private:
CSingleton() {}
~CSingleton() {}
static std::unique_ptr<T> m_pInstance;
};
template <typename T>
std::unique_ptr<T> CSingleton<T>::m_pInstance(nullptr);
#endif //_SINGLETON_H_
拿LOG系统做示范
Log.h
#ifndef _LOG_H_
#define _LOG_H_
#pragma once
#include <string>
#include "Singleton.h"
#include "EnumDef.h"
class CLog
{
CLog(const CLog&) = delete;
const CLog& operator=(const CLog&) = delete;
public:
bool Init();
void Fini();
CLog();
~CLog();
void WriteLog(LOG_LEV eType, const char* file, const char* func, int line, const char* pszFormat, ...);
private:
char m_szPath[256];
std::string m_strLev;
};
#define FILENAME(x) strrchr(x, '\\') ? strrchr(x, '\\') + 1 : x
#define LOG (*CSingleton<CLog>::GetInstance())
#define LOGDEBUG(format, ...) LOG.WriteLog(LOG_LEV_DEBUG, FILENAME(__FILE__), __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOGINFO(format, ...) LOG.WriteLog(LOG_LEV_INFO, FILENAME(__FILE__), __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOGWARN(format, ...) LOG.WriteLog(LOG_LEV_WARN, FILENAME(__FILE__), __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#define LOGERROR(format, ...) LOG.WriteLog(LOG_LEV_ERROR, FILENAME(__FILE__), __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
#endif //_LOG_H_
Log.cpp
#include "Log.h"
#include <direct.h>
#include <io.h>
#include <time.h>
#include <stdarg.h>
#include <assert.h>
using namespace std;
bool CLog::Init()
{
if (!_getcwd(m_szPath, 256))
return false;
//设置log目录
strcat_s(m_szPath, "\\..\\log\\");
if (_access(m_szPath, 6))
{
if (_mkdir(m_szPath) == -1)
{
return false;
}
}
return true;
}
void CLog::Fini() {}
CLog::CLog()
{
memset(m_szPath, 0, 256);
}
CLog::~CLog() {}
void CLog::WriteLog(LOG_LEV eType, const char* file, const char* func, int line, const char* pszFormat, ...)
{
//获取时间
tm t; // tm结构指针
time_t now; //声明time_t类型变量
time(&now); //获取系统日期和时间
localtime_s(&t, &now);
//创建日志文件
FILE* fp;
char LogName[255];
//按照日志类型创建不同日志文件
switch (eType)
{
case LOG_LEV_ERROR:
m_strLev = "err";
break;
case LOG_LEV_DEBUG:
m_strLev = "debug";
break;
case LOG_LEV_INFO:
m_strLev = "info";
break;
case LOG_LEV_WARN:
m_strLev = "warn";
break;
default:
break;
}
snprintf(LogName, 255, "%s%s%d-%d-%d.log", m_szPath, m_strLev.c_str(), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
fopen_s(&fp, LogName, "a+");
assert(fp);
char szContent[512];
//日志内容格式化
const char* formatHead = "%d-%d-%d\t%02d:%02d:%02d\t%s\t%s\t%d\t";
int n = snprintf(szContent, 256, formatHead, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, file, func, line);
//写入内容,并换行
va_list valist;
va_start(valist, pszFormat);
vsnprintf(szContent + n, 256, pszFormat, valist);
fputs(szContent, fp);
fprintf(fp, "\n");
va_end(valist);
}
使用示范
LOG.Init();
//启动WinSock2环境
WSADATA wsaData;
if (!WSAStartup(MAKEWORD(2, 2), &wsaData))
{
LOGERROR("WSAStartup Err");
return 0;
}
这边没有调用LOG.Fini(),原因是Log系统中没有需要释放的资源,故不写