C++ 静态局部变量重新初始化
我有一个虚拟的单例,我想为它实现C++ 静态局部变量重新初始化,c++,gcc,c++11,singleton,C++,Gcc,C++11,Singleton,我有一个虚拟的单例,我想为它实现getInstance()静态函数,但是每次调用它时,静态对象都会被重新初始化,所以每次我都会得到一个新实例,任何帮助都将不胜感激-这让我非常困惑 我要在其中实现该方法的类: class Pc : public Machine { private: ... members ... public: static Pc* getInstance(); Pc() {}; virtual ~Pc() {} ... ot
getInstance()
静态函数,但是每次调用它时,静态对象都会被重新初始化,所以每次我都会得到一个新实例,任何帮助都将不胜感激-这让我非常困惑
我要在其中实现该方法的类:
class Pc : public Machine
{
private:
... members ...
public:
static Pc* getInstance();
Pc() {};
virtual ~Pc() {}
... other functions ...
};
父类:
class Machine
{
public:
static Machine* getInstance();
Machine() { }
Machine(const Machine&) = delete;
virtual ~Machine() { }
... methods ...
void operator=(const Machine&) = delete;
};
从机器到Pc的桥接->单例
Machine* Machine::getInstance()
{
return Pc::getInstance();
}
我有两套个人电脑的代码,一套我认为应该可以用,还有我目前的变通代码
非工作代码:
Pc* Pc::getInstance()
{
static Pc* pc = new Pc();
return pc;
}
正在工作(但已停止)getInstance()
code:
static Pc* pc = nullptr;
Pc* Pc::getInstance()
{
if(pc == nullptr) {
pc = new Pc();
}
return pc;
}
虽然这两个函数都编译成功,但在中断指向代码后,我可以看到预期的代码返回相同的指针,但是在操作对象后,第二个调用返回一个新对象,这使我相信静态变量已再次初始化
使用以下标志编译:
-ffreestanding -Wall -Wextra -fno-exceptions -fno-rtti -std=gnu++11 -lgcc
(这是针对操作系统项目的)
。。。这让我相信静态变量已经被再次初始化了
从允许公开构造(或复制)Machine
和Pc
实例的角度来看,这可能是一种正确的看法
你的代码在这里
Pc* Pc::getInstance() {
static Pc* pc = new Pc();
return pc;
}
以及方法的签名
static Machine* getInstance();
最好是
Pc& Pc::getInstance() {
static Pc theInstance;
return theInstance;
}
static Machine& getInstance();
同时为两个类Machine
和Pc
private设置默认、复制构造函数和赋值运算符。
因此,实际上只能使用引用变量来访问singleton实例
Machine& mach = Pc::getInstance();
Machine m2; // Fails to compile
更新:但我看到了一个普遍的问题,这让你的整个设计有点可疑:
Machine& Machine::getInstance() {
return Pc::getInstance();
}
这使得机器
类依赖于它的派生类,这使得基类毫无用处
使用模板类来解决这个问题怎么样
template<class Derived>
class Machine {
public:
static Derived& getInstance() {
static Derived theInstance;
return theInstance;
}
protected:
Machine() {
Derived* self = static_cast<Derived*>(this); // Ensure that Derived
// inherits from Machine
(void)self; // suppress compiler warning for unused variable
}
private:
Machine(const Machine&);
Machine& operator=(const Machine&);
};
class Pc : public Machine<Pc> {
friend class Machine<Pc>;
Pc() : Machine<Pc>() {}
};
int main() {
Pc& pc = Pc::getInstance(); // Get a reference of the Pc singleton
return 0;
}
模板
类机器{
公众:
静态派生&getInstance(){
静态导引头;
返回指令;
}
受保护的:
机器(){
派生*self=static_cast(this);//确保派生
//继承自机器
(void)self;//抑制未使用变量的编译器警告
}
私人:
机器(const Machine&);
机器和操作员=(常数机器和);
};
Pc类:公共机器{
朋友级机器;
Pc():机器(){}
};
int main(){
Pc&Pc=Pc::getInstance();//获取Pc单例的引用
返回0;
}
见a
至于您提到的
-ffreestanding
编译器选项:
首先,它是C编译器选项(不应该影响C++代码),其次是我在
中发现的 GCC的目标是可用作一致性独立实现,或用作一致性托管实现的编译器。默认情况下,它将充当托管实现的编译器,将STDC_hosted定义为1,并假定使用ISO C函数的名称时,它们具有标准中定义的语义。要使其作为独立环境的一致独立实现,请使用选项-ffreestanding;然后,它将STDC_HOSTED定义为0,并且不会对标准库中函数名的含义进行假设,以下列出了例外情况。要构建操作系统内核,您可能仍然需要自行安排链接和启动。看这并没有给我任何关于本地静态初始化的未定义行为的观点。好的!经过3天的挠头,我已经找到了错误的原因!如果您使用
--ffreestanding
编译您的代码,GCC希望您为自己提供一些函数,以防其他人有此错误(尽管非常模糊),我将我使用的代码放在下面(非常感谢这段代码!!)
我不确定这是否会对您的问题产生任何影响,但是应该声明单例构造函数
私有
,第二种方式(工作方式)不是创建单例实例的方式吗?“不工作”的方式每次调用时都会创建一个新的Pc
。@bstar55是的,他们应该这样做,但我一直在尝试让它工作,这是摆弄代码留下的-遗憾的是,无论哪种方式,代码都不工作。@gta0004静态变量应该做完全相同的事情-在调用之间保留其值@gta0004不,没有。函数本地静态将初始化一次。。。第一次控制流通过初始化。机器为许多不同的体系结构(Pc/Mac等)实现方法,因此基类实现全局可用的函数,其中派生类实现进一步的变量类型,以及一些虚拟函数的实现。此外,这段代码仍然无法工作-Pc构造函数像以前一样被多次调用,使用静态局部变量的要求是什么?我在编译时使用-ffreestanding这是否会删除对它们的支持?@Mattiemus“机器为许多不同的体系结构实现方法”使用这种模式仍然可以很好地完成以及一些虚拟函数的实现。“我的提案中根本不需要虚拟函数(请参见静态\u cast
了解自我
)。我想你一次需要一个架构,对吗?我实际上找不到关于-ffreestanding
编译器选项(您有吗?)的文档,但我怀疑它是否真的会影响本地静态初始化的行为。这是从当前C++标准中定义的。ῥεῖ, 我也为单身人士使用CRTP模式。到目前为止,它运作良好。顺便说一句,你错过了函数中的return语句。我今天有更多的时间来测试这段代码-但是它仍然不工作,在第二次调用getInstance()时再次调用机器构造函数,但是指针保持不变(中断p
__extension__ typedef int __guard __attribute__((mode(__DI__)));
extern "C" int __cxa_guard_acquire(__guard* g)
{
return !*(char*)(g);
}
extern "C" void __cxa_guard_release(__guard* g)
{
*(char *)g = 1;
}
extern "C" void __cxa_guard_abort (__guard*)
{
}