c++ - 静态局部变量被重新初始化

标签 c++ gcc c++11 singleton

我有一个虚拟单例,我想为其实现 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* Pc::getInstance()
{
    static Pc* pc = new Pc();
    return pc;
}

工作(但有问题)getInstance() 代码:

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

(这是一个操作系统项目)

最佳答案

... leading me to believe the static variable as been initialized again.

从您允许公开构造(或复制)MachinePc 实例的角度来看,这可能是一种正确的看法。

好吧,你的代码在这里

Pc* Pc::getInstance() {
    static Pc* pc = new Pc();
    return pc;
}

和方法的签名

static Machine* getInstance();

最好是

Pc& Pc::getInstance() {
    static Pc theInstance;
    return theInstance;
}

static Machine& getInstance();

还使 MachinePc 类的默认、复制构造函数和赋值运算符成为私有(private)的。 因此实际上只能使用引用变量来访问单例实例

Machine& mach = Pc::getInstance();
Machine m2; // Fails to compile

更新:
但我在这里看到一个普遍的问题,这让你的整个设计有点可疑:

Machine& Machine::getInstance() {
    return Pc::getInstance();
}

这使得 Machine 类依赖于它的派生类,这使得基类完全没有用。


使用模板类来解决这个问题怎么样?

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;
}

查看 fully working sample here .


至于你提到的 -ffreestanding 编译器选项:

首先,它是一个 c 编译器选项(不应影响您的 c++ 代码),其次,正如我在 GCC documentation 中找到的那样

GCC aims towards being usable as a conforming freestanding implementation, or as the compiler for a conforming hosted implementation. By default, it will act as the compiler for a hosted implementation, defining STDC_HOSTED as 1 and presuming that when the names of ISO C functions are used, they have the semantics defined in the standard. To make it act as a conforming freestanding implementation for a freestanding environment, use the option -ffreestanding; it will then define STDC_HOSTED to 0 and not make assumptions about the meanings of function names from the standard library, with exceptions noted below. To build an OS kernel, you may well still need to make your own arrangements for linking and startup. See Options Controlling C Dialect.

这没有给我任何关于本地静态初始化的未定义行为的观点。

关于c++ - 静态局部变量被重新初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24173910/

相关文章:

android - 将 Windows C++ 用于 Android 和 iOS

c++ - 导出制造商、符号可见性……?

c++ - 使用 MinGW 和 Eclipse 编译 Win32 GUI 应用程序(没有控制台)

c++ - C++内存对齐是正确的还是低效的?

c++ - 仅使用一个参数(整数 vector )和第一个元素作为枢轴的快速排序

bash - 如何通过管道传递 gcc 或 gfortran 警告和错误

c - GCC 无法从具有内联汇编的函数生成 32 位代码

c++ - 如何正确删除那些指针?

C++11/lambda 函数和函数指针

c++ - 从具有相同容器类型但不同 value_type 的容器生成新类型