静态局部变量被重新初始化
Static local variable gets reinitialized
我有一个虚拟的单例,我想实现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;
};
Bridge from Machine -> Pc singleton
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
(这是一个OS项目)
…让我相信静态变量又被初始化了
如果允许公开构建(或复制)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。因此,实际上只能使用引用变量来访问单例实例
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;
}
查看完整的工作示例。
至于你提到的-ffreestanding
编译器选项:
首先,它是一个c编译器选项(不应该影响您的c++代码),其次,正如我在GCC文档
中发现的那样GCC的目标是作为一个符合标准的独立实现可用,或者作为一个符合标准的托管实现的编译器。默认情况下,它将充当宿主实现的编译器,将STDC_HOSTED定义为1,并假设在使用ISO C函数的名称时,它们具有标准中定义的语义。要使其作为独立环境的符合标准的独立实现,请使用选项- freestanding;然后它将STDC_HOSTED定义为0,并且不假设来自标准库的函数名的含义,例外情况如下所示。要构建OS内核,您可能仍然需要自己安排链接和启动。
这并没有给我任何关于局部静态初始化的未定义行为的点
Ok!经过3天的挠头,我找到了错误的原因!如果你使用--ffreestanding
来编译你的代码,GCC希望你为自己提供一些函数,以防其他人有这个(授予非常模糊的)错误,我把我使用的代码放在下面(非常感谢osdev.org的这段代码!!)
__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*)
{
}
- 未初始化的变量有什么危险
- 使用的未初始化局部变量'Quick'
- C++如何通过"constructor initialization"初始化行变量?
- "local scope"中的 C++ 初始化静态变量
- 为什么我的 c++ 程序检查不是初始化的变量?
- 使用大括号或括号初始化成员变量
- 使用 std::ios_base::Init 正确初始化全局变量
- 'auto *x = new some_struct{};"是一个未初始化的变量?
- 是否可以将已经初始化的变量转换为 void*?
- Clang++ 6.0 内存清理器未报告返回值指示条件分支的函数中的未初始化局部变量
- 为什么默认情况下初始化局部变量
- 如果仅在 lambda 中使用,则不会在发布版本中初始化局部静态变量
- 对初始化时使用的未初始化局部变量感到困惑
- 如何在Qt(gcc 64位)中禁用自动初始化局部变量
- 在函数中初始化局部变量时出现问题
- 为什么VS编译器不会在C++上自动初始化局部变量?
- C++构造函数:在初始化器列表之前初始化局部变量
- 如何初始化局部联合变量
- 实际初始化的未初始化局部变量
- 收到未初始化局部变量的警告