【发布时间】:2020-02-08 16:19:58
【问题描述】:
嗯,我在自己的项目中使用单例。最常用的单例实现可能是 Meyer 的单例以及使用 std::call_once 或 pthread_once 的单例。对于并行计算,它们都是线程安全的
//Meyer's singleton
class MySingleton{
public:
static MySingleton& getInstance(){
static MySingleton instance;
// volatile int dummy{};
return instance;
}
private:
MySingleton()= default;
~MySingleton()= default;
MySingleton(const MySingleton&)= delete;
MySingleton& operator=(const MySingleton&)= delete;
};
//with call_once
class MySingleton{
public:
static MySingleton& getInstance(){
std::call_once(initInstanceFlag, &MySingleton::initSingleton);
// volatile int dummy{};
return *instance;
}
private:
MySingleton()= default;
~MySingleton()= default;
MySingleton(const MySingleton&)= delete;
MySingleton& operator=(const MySingleton&)= delete;
static MySingleton* instance;
static std::once_flag initInstanceFlag;
static void initSingleton(){
instance= new MySingleton;
}
};
MySingleton* MySingleton::instance= nullptr;
std::once_flag MySingleton::initInstanceFlag;
Meyer 的实现使用局部静态变量来确保线程安全并返回实例标识,而后者通过 call_once 实现并返回指针。在我的实验中,Meyer 的实现速度更快一些。但是大多数项目使用 call_once 方法进行最基本的单例实现,尽管项目的一些小组件使用了 Meyer 的实现。我只是想知道有什么原则可以遵循,这两种不同的实施方式的优缺点是什么?
【问题讨论】:
-
恕我直言,基本上,两个实现是相同的。 Meyer 的实现要优雅一些。例如,在这种情况下,第二个实现有一个不必要的
initSingleton方法。但是,如果初始化会更复杂,这个方法也很有用。 -
Meyer 的实现对“Destruction Order Fiasco”是明智的,见DOF,而第二个是内存泄漏明智......
-
Meyer 唯一的破坏顺序风险是,如果您的破坏依赖于不是“正确”单例的静态对象,例如
std::cout和std::cin。第二种方法不提供在析构函数中清理代码的机会。
标签: c++ parallel-processing singleton