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*)
{
}