最近我碰到了C++的Singleton设计模式的实现/实现.看起来像这样(我从现实生活中采用了它):
// a lot of methods are omitted here
class Singleton
{
public:
static Singleton* getInstance( );
~Singleton( );
private:
Singleton( );
static Singleton* instance;
};
Run Code Online (Sandbox Code Playgroud)
从这个声明我可以推断出实例字段是在堆上启动的.这意味着存在内存分配.对我来说完全不清楚的是,什么时候内存将被解除分配?还是有漏洞和内存泄漏?好像在实施中存在问题.
我的主要问题是,如何以正确的方式实施它?
我知道这是一个经常被问到的问题,但由于有很多变种,我想重新陈述它,并希望有一个反映当前状态的答案.就像是
Logger& g_logger() {
static Logger lg;
return lg;
}
Run Code Online (Sandbox Code Playgroud)
变量lg的构造函数是否保证只运行一次?
我从以前的答案中知道,在C++ 03中,这不是; 在C++ 0x草案中,这是强制执行的.但我想要一个更明确的答案
在一次采访中询问了这个问题.第一部分是编写单例类:
class Singleton
{
static Singleton *singletonInstance;
Singleton() {}
public:
static Singleton* getSingletonInstance()
{
if(singletonInstance == null)
{
singletonInstance = new Singleton();
}
return singletonInstance;
}
};
Run Code Online (Sandbox Code Playgroud)
然后我被问到如何getSingletonInstance()在多线程情况下处理这个问题.我不太确定,但我修改为:
class Singleton
{
static Singleton *singletonInstance;
Singleton() {}
static mutex m_;
public:
static Singleton* getSingletonInstance()
{
m_pend();
if(singletonInstance == null)
{
singletonInstance = new Singleton();
}
return singletonInstance;
}
static void releaseSingleton()
{
m_post();
}
};
Run Code Online (Sandbox Code Playgroud)
然后有人告诉我,虽然需要一个互斥锁,但挂起和发布互斥锁效率不高,因为需要时间.并且有一种更好的方法来应对这种情况.
有没有人知道在多线程情况下处理单例类的更好,更有效的方法?
保证在C++标准首次使用时实例化静态本地.但是,我想知道如果我在构建时访问静态本地对象会发生什么.我认为这是UB.但在以下情况下避免这种情况的最佳做法是什么?
Meyers Singleton模式在静态getInstance()方法中使用静态局部来在第一次使用时构造对象.现在,如果构造函数(直接或indireclty)getInstance()再次调用,我们将面临静态初始化尚未完成的情况.这是一个最小的例子,它说明了问题情况:
class StaticLocal {
private:
StaticLocal() {
// Indirectly calls getInstance()
parseConfig();
}
StaticLocal(const StaticLocal&) = delete;
StaticLocal &operator=(const StaticLocal &) = delete;
void parseConfig() {
int d = StaticLocal::getInstance()->getData();
}
int getData() {
return 1;
}
public:
static StaticLocal *getInstance() {
static StaticLocal inst_;
return &inst_;
}
void doIt() {};
};
int main()
{
StaticLocal::getInstance()->doIt();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在VS2010中,这没有问题,但VS2015死锁.
对于这种简单,减少的情况,显而易见的解决方案是直接呼叫getData(),而无需getInstance()再次呼叫.但是,在更复杂的情况下(根据我的实际情况),这种解决方案是不可行的.
如果我们改变getInstance()方法来处理像这样的静态局部指针(从而放弃Meyers Singleton模式):
static StaticLocal …Run Code Online (Sandbox Code Playgroud) 我有一个琐碎的单身课程.我的singleton.h文件看起来像这样:
class singleton
{
...
public:
static singleton& instance();
};
Run Code Online (Sandbox Code Playgroud)
我singleton.cpp看起来像这样:
...
singleton& singleton::instance()
{
static singleton * const _instance(new singleton);
return *_instance;
}
Run Code Online (Sandbox Code Playgroud)
在编写这个类时,我认为我依赖于线程安全的函数本地静态初始化,我理解这将在这里描述的C++标准的第6.7节中阐述.希望我明白这是如何工作的.
我正在使用2013年11月的CTP工具链运行Visual C++ .微软称2013年11月CTP支持线程安全的函数本地静态初始化,并快速浏览编译器生成的目标代码,表明它正在尝试这样做.
我的问题是,在另一个翻译单元中销毁静态存储持续时间对象需要访问singleton::instance().我预计这不会有任何困难,因为静态变量支持singleton::instance()是一个永不删除的指针.但是,singleton::instance()来自该其他对象的调用正在崩溃我的进程,堆栈跟踪如下所示:
_Init_thread_header
singleton::instance
other_translation_unit_object::~other_translation_unit_object
Run Code Online (Sandbox Code Playgroud)
其中_Init_thread_header()似乎是由编译器插入来实现线程安全的静态初始化.
所以我的问题是:上面的代码是否表明我从根本上误解了静态初始化应该如何工作(最可能的情况是,如果是这样,那就好了:),或者是否有可能出现其他问题?
我们正在使用奇怪的重复模板模式来实现单例.但是,在最近的Clang版本中,我们得到了一个-Wundefined-var-template警告.建议的修复是添加"显式实例化声明".
我试图这样做,但后来我在编译单元中获得了"实例化后显式特化"的错误,其中单例模板类成员变量的定义是.
解决此警告突出显示的问题的适当构造是什么?
简化细节(已删除大部分逻辑,以制作MCVE):
SingletonBase.hh:
template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};
Run Code Online (Sandbox Code Playgroud)
Singleton.hh:
#include "SingletonBase.hh"
class Singleton : public SingletonBase< Singleton > {
friend class SingletonBase< Singleton >;
public:
int do_stuff(int v) { return v+2; }
private:
static Singleton * create_singleton_instance() {
return new Singleton;
}
};
Run Code Online (Sandbox Code Playgroud)
Singleton.cc:
#include "Singleton.hh"
template …Run Code Online (Sandbox Code Playgroud) 我正在尝试同时实现单例模式和工厂模式。在我看来,每种工厂只能有一个工厂,它们基于一个抽象类,并使用工厂来生产相应的shape对象。
但我收到一个错误:
错误LNK2001:无法解析的外部符号“私有:静态类TriangleFactory * TriangleFactory ::实例”(?instance@TriangleFactory@@0PAV1@A)
我不知道为什么会发生这种情况。你能告诉我如何解决它吗?代码如下。
#include<type_traits>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<memory>
#include<time.h>
using namespace std;
class Shape
{
public:
virtual void display();
protected:
int x, y;
};
class MyTriangle:public Shape
{
public:
MyTriangle(int _x, int _y)
{
x = _x;
y = _y;
}
MyTriangle()
{
x = rand() % 200;
y = rand() % 200;
}
void display()
{
printf("%d %d\n",x,y);
}
};
class SuperFactory
{
public:
virtual Shape* Execute() = 0;
};
class TriangleFactory :public …Run Code Online (Sandbox Code Playgroud)