我试图用c ++中的threadsafe实践编写一个日志类。现在问题是,我希望对每个日志行的调用非常简单。我可以使用下面的静态类方式:
//Calling this in some GUI initialization point of application
CLogger::InitLogger("LogFile.log");
//Calling below from any class just adding the header to the cpp
CLogger::Log("Some informational text goes here");
现在这并不遵循OOP,所以想要使用单例类。
//Singleton log class
class CLogWrite
{
public:
static CLogWrite* GetInstance();
private:
static CLogWrite *pInstance;
void Log();
};
CLogWrite* CLogWrite::GetInstance()
{
if(pInstance != NULL)
{
pInstance = new CLogWrite;
}
return pInstance;
}
void CLogWrite::Log()
{
//threadSafe lock
//write 'logText' to file here
//threadSafe unlock
}
现在问题是,如果我在类上面编写并在我的GUI类init函数中调用CLogWriter :: GetInstance(),如下所示:
//single logger instance for my app
CLogWriter *mLogInstance;
mLogInstance = CLogWriter::GetInstance()
我需要通过' mLogInstance'变量到我想要编写日志的项目中的每个类。但我不想那样做。
什么是最好的方法?
答案 0 :(得分:2)
试试这个:
class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
Singleton(Singleton const&) = delete;
void operator=(Singleton const&) = delete;
private:
Singleton() {};
};
答案 1 :(得分:1)
我最喜欢的C ++技术之一就是所谓的CRTP,它可以用来实现单例逻辑。看看这段代码:
template <class Type>
class Singleton
{
private:
static std::unique_ptr<Type> _holder_ptr;
static std::mutex _mutex;
public:
static Type& GetSingleton()
{
if(!_holder_ptr)
_create_instance();
return *(_holder_ptr.get());
}
protected:
static void _create_instance()
{
_mutex.lock();
if(!_holder_ptr)
_holder_ptr.reset(new Type());
_mutex.unlock();
}
};
现在,您可以使用此类来定义&#34;单身&#34;:
class Log : public Singleton<Log>
{
//content
};
并使用它:
Log& global_log = Log::GetSingleton();
//do something
这是C ++ 11的版本。对于较旧的编译器,请将std::mutex
替换为与平台相关的同步原语。在Windows上,您可能希望使用CRITICAL_SECTION。示例用法:here。
std::unique_ptr
也在C ++ 11中引入,因此您可以将其替换为std::auto_ptr(在C ++ 11中弃用),使用smart pointer from Boost library或创建自己的解决方案(这并不困难) ,但重新发明轮子不是一个好主意。)
请注意,此Singleton
并不禁止创建Log
的其他实例 - 而且它不应该!有两种常见的情况:
Log
的其他实例,但同时要求,必须至少存在一个此类对象。然后,简单派生自Singleton
就是你所需要的。Log
为真&#34; Singleton&#34;,即:只有一个共享实例可以存在 - 其余代码必须使用此实例,因此一切都可以按预期工作。在这种情况下,使用= delete
语法删除默认构造函数,复制构造函数和赋值运算符(或简单地将它们声明为protected
或private
,具体取决于编译器对= delete
语法的支持)。另外,请记住,如果您想将共享实例作为指针,您需要使用某种智能指针,如上所示。您不能像在原始解决方案中那样使用普通指针:
CLogWrite* CLogWrite::GetInstance()
{
if(pInstance != NULL)
{
pInstance = new CLogWrite;
}
return pInstance;
}
pInstance
何时何地被销毁?怎么样?