C++Singleton类创建多个实例
C++ Singleton class creates more than one instance
静态方法GetUI是用鼠标事件调用的,但从调试中注意到,在极少数情况下,构造函数会用鼠标事件的冲击调用两次。
问题是调度程序在构建过程中停止,切换到另一个任务进程调用,该调用也开始创建另一个实例?
Object* Interface::instance = 0;
Object* Interface::GetUI() {
if (instance == 0) {
instance = new Interface();
}
return instance;
}
您实际上应该锁定singleton,否则,在多线程时,您将创建多个实例
对于C++11,您可以按如下方式使用它。
#include <mutex>
class Singleton
{
static Singleton *singletonInstance;
Singleton() {}
static std::mutex m_;
public:
static Singleton* getSingletonInstance()
{
std::lock_guard<std::mutex> lock(m_);
if(singletonInstance == nullptr)
{
singletonInstance = new Singleton();
}
return singletonInstance;
}
}
您所描述的行为只能在从多个线程使用GetUI
时出现。我希望您知道,如果没有适当的锁定或使用排队的方法调用,就无法对GUI方法进行任何直接调用。
下面显示了在Qt中创建全局变量的线程安全、惯用的方法。真的没有理由再实施一次。有时NIH很糟糕。
#include <QtGlobal>
class Object {};
class Interface {
public:
static Object * GetUI();
};
// This must be in a *single* source file *only*. Not in header!
Q_GLOBAL_STATIC(Object, interfaceInstance)
Object* Interface::GetUI() {
return interfaceInstance;
}
问题在于对象的创建和实例化。有两个可能的解决方案;可以同步CCD_ 2功能,正如Jerry YY所建议的,或者您可以确保singleton在开始线程处理之前创建;只出现竞争条件当您在至少一个线程中修改对象时您已经创建了对象,instance
永远不会被修改。
一种方法是简单地定义Interface::instance
作为:
Object* Interface::instance = Interface::GetUI();
零初始化确保Interface::GetUI
调用,Interface::instance
初始化为null指针,并且进行静态对象的初始化在CCD_ 7之前。
否则:如果你确信Interface::GetUI
永远不会在进入main
之前调用(考虑到你说过;在你之前不应该有任何鼠标事件输入main
(,然后可以放弃测试(或将其替换为assert( instance != nullptr
(在Interface::GetUI
中写入:
Object* Interface::instance = new Interface();
简单多了,避免了所有的问题。
这里有一个更好的带有模板的单例实现:
template <class T>
class Singleton
{
private:
static T * _instance;
protected:
Singleton (){}
public:
static T & get()
{
if (_instance)
{
return *_instance;
}
_instance = new T();
return *_instance;
}
};
template <class T> T* Singleton<T>::_instance = 0;
现在用继承实现它:
class Foo : public Singleton<Foo>
并在任何地方使用:
Foo::get().DoSomething();
这是早期解决方案的更快版本(减少了互斥体开销的使用(。
#include <mutex>
class Singleton
{
static volatile Singleton * singletonInstance;
Singleton() {}
static std::mutex m_;
public:
static Singleton* getSingletonInstance()
{
if(singletonInstance == nullptr)
{
std::lock_guard<std::mutex> lock(m_);
if(singletonInstance == nullptr) {
Singleton *tmp = new Singleton(); // fight with compiler see link in comment
singletonInstance = tmp;
}
}
return singletonInstance;
}
}
无论如何,我不相信多线程是一个问题,因为您已经写过鼠标事件,这应该只来自主线程。添加断言Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread())
以确保这是同步的问题(如果它失败,请检查调用堆栈(。
我还建议禁用赋值运算符和复制构造函数。
您的实例和GetUI((方法必须是静态的。
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 为什么创建友元类的实例会导致"undefined reference to"错误?
- 在C++中为链表类创建实例
- 如何为类的每个实例创建特定实例的方法
- 基于现有实例创建类的新实例
- 从模板类的另一个实例创建模板类的实例时省略模板参数
- Vulkan-加载扩展时实例创建失败
- 通知B1或B2或B3类的特定实例创建Pointer A类
- 使用std::shared_ptr对象实例创建boost::线程
- 如何在C++中仅包含一个实例创建类
- 如何从旧实例创建新实例
- 在V8 javascript引擎中,如何为每个实例创建一个重新使用ObjectTemplate的构造函数
- 有没有一种方法可以从基本实例创建派生实例
- 如何在修改设计时停止现有代码基类的实例创建
- 使用基类实例创建派生类实例
- 如何从另一个仅静态选择满足特定类型规则的索引的元组实例创建元组实例