c++单例类实例访问整个应用程序



我正试图用c++编写一个具有线程安全实践的日志类。现在的问题是,我想让对每个日志行的调用变得非常简单。我可以采用如下静态课堂方式:

//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类。

//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"变量传递给我的项目中的每个类,从那里我想写日志。但我不想那样做。

什么是最好的方法?

试试这个:

class Singleton
{
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
Singleton(Singleton const&) = delete;
void operator=(Singleton const&) = delete;
private:
Singleton() {};        
};

我在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();
}
};

现在,您可以使用这个类来定义"singletons":

class Log : public Singleton<Log>
{
//content
};

并使用它:

Log& global_log = Log::GetSingleton();
//do something

这是C++11的版本。对于较旧的编译器,请将std::mutex替换为与平台相关的同步原语。在Windows上,您可能需要使用CRITICAL_SECTION。示例用法:此处。

std::unique_ptr也在C++11中引入,因此您可以将其替换为std::auto_ptr(在C++11中已弃用),使用Boost库中的智能指针或创建自己的解决方案(这并不难,但重新发明轮子不是一个好主意)。

请注意,此Singleton并不禁止创建Log的其他实例,而且不应该!有两种常见场景:

  • 允许用户创建Log的其他实例,但同时要求至少存在一个这样的对象。那么,从Singleton中简单地派生就是您所需要的
  • 您需要Log是真正的"Singleton",也就是说:只有一个共享实例可以存在——其余的代码必须使用这个实例,这样一切都可以按预期工作。在这种情况下,使用= delete语法删除默认构造函数、复制构造函数和赋值运算符(或者简单地将它们声明为protectedprivate,具体取决于编译器对= delete语法的支持)

另外,请记住,如果您想将共享实例作为指针,则需要使用某种智能指针,如上所述。您不能像在原始解决方案中那样使用纯指针:

CLogWrite* CLogWrite::GetInstance()
{
if(pInstance != NULL)
{
pInstance = new CLogWrite;
}
return pInstance;
}

pInstance将在何时何地销毁?怎样

相关内容

最新更新