C++静态变量为何只能初始化一次

本文详细解析了C++中静态变量的工作机制,包括全局变量、函数的使用方式,强调了静态变量只初始化一次的特点,并通过代码实例演示了如何验证这一特性。文章还提供了深入学习静态变量的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://blog.youkuaiyun.com/kelleniiii/article/details/7576779?reload

static 关键字的作用:

static全局变量是限定作用域的全局变量
     static函数只能被本文件里的内容使用(相当于私有函数),是限定作用域的全局函数。
     C++里头的static函数是相对成员函数而言,其调用对象是类,而不是对象
     C++在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝; 
     C++在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。
=========================================================================

童鞋们在学习C++的时候,往往只是按照书本上的原文去强行记忆各种特性,比方说,静态变量只初始化一次。你心中一定在默念:一定要记住,static只会初始化一次云云,希望自己能够记住。告诉你,你为什么总是记不住,因为你没有正真理解静态变量的原理, 所以下面我就来告诉大家它的原理,直接上代码:

[code=C/C++]
#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
int initNum = 3;
for (int i=5; i > 0; --i)
{
static int n1 = initNum;
n1++;
printf("%d\n", n1);

}


getchar();
return 0;
}
[/code]
输出结果:
4
5
6
7
8


在这里我们可以看到虽然代码循环了5次,静态变量n1确实只初始化了一次。那么为什么呢?继续上代码,相信大家就会明白些许了。
[code=C/C++]
int _tmain(int argc, _TCHAR* argv[])
{
int initNum = 3;
for (int i=5; i > 0; --i)
{
static int n1 = initNum;

//我们在这里增加了两句代码,把n1所指的内存地址后面4个字节赋值成0
int* p = &n1;
p++;
*p = 0;
//end

n1++;

printf("%d\n", n1);

}

getchar();
return 0;
}
[/code]
输出结果:
4
4
4
4
4

这次,静态变量居然跟随着5次循环也初始化了5次。你一定非常诧异,其实我们不难推断,其实静态变量就是通过静态变量后面的一个32位内存位来做记录,以标识这个静态变量是否已经初始化。而我们的p++;*p = 0;却每次都将这个值赋值为0,所以程序就一直认为n1一直没有被初始化过,并每次都初始化一次。看一下内存,就更明了了:
0x00E8716C  03 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 b0 e7 1e 6a 00 00 00
这里的内存地址就是静态变量n1的地址,值是3,后面还有一个1,你看到了吗,这个就是程序用来记录该静态变量是否初始化的标识位啦。现在你一定明白原理了,并且能轻松记住静态变量的特性了吧?
童鞋们还可以试一下,多个静态变量时,标识位的表示形式,以深入学习(透露一下,每一位标识一个静态变量的初始化状态)。
以上代码有一点需要说明:代码中之所以要用int initNum = 3;而不是直接用static int n1 = 3;是因为如果给静态变量直接赋值一个常量的话,编译器会进行优化,导致程序在一启动时,就初始化好了,不便于我们观察静态变量内存上的改变。
### 静态变量初始化一次的行为特性及其原因 #### 1. **静态变量的生命周期** 静态变量的生命周期贯穿整个程序运行期间。无论它是全局静态变量还是局部静态变量,一旦被初始化后,其值在整个程序执行过程中都保持有效[^1]。这意味着即使函数调用结束或者类实例销毁,静态变量仍然存在并保留上次的状态。 对于类中的静态成员变量而言,它属于整个类而非某一具体对象。因此,它的初始化过程只会在第一次加载时发生,并且不会随着每次新对象的创建而重新初始化[^2]。 #### 2. **为什么静态变量只能初始化一次?** 这是由C++的设计原则决定的——为了确保数据的一致性和可预测性。如果允许静态变量多次初始化,则可能导致不可预期的结果或冲突状态。例如: - 当多个源文件包含同一个头文件时,重复定义可能会引起链接器错误。 - 若在构造函数中尝试再次初始化静态成员变量,则可能覆盖原有的值,破坏共享资源的安全性。 为了避免上述问题,标准规定任何静态变量(无论是全局范围内的还是作为类的一部分)在其生存期内仅能有一次有效的赋初值操作[^3]。 #### 3. **静态变量存储位置的影响** 从底层实现角度来看,在编译阶段就已经决定了静态变量最终会被分配到特定的内存区域(.data 或 .bss段)[^4]: - 已经显式赋予数值的静态变量存放在`.data`区; - 没有指定初始值得则放入`.bss`区,默认置零。 这种安排进一步强化了一条规则:即这些变量自始至终维持单一版本的存在形式,从而支持它们“唯一”的本质属性。 #### 4. **特殊情况下的注意事项-QT环境中的应用案例** 值得注意的是,在某些框架下(如QT),尽管遵循常规逻辑完成了静态变量设置工作,但由于额外机制介入可能出现特殊状况。比如提到过的关于单例模式的应用场景里,因为事件循环结束后才触发清理动作,所以即便看似合理设计也可能隐藏潜在风险。 ```cpp class Singleton { private: static Singleton* instance; public: static Singleton* getInstance() { if (!instance){ instance = new Singleton(); } return instance; } ~Singleton(){ qDebug()<<"Destroying singleton"; } }; // Initialization outside the class definition. Singleton* Singleton::instance = nullptr; int main(int argc, char *argv[]) { QApplication app(argc, argv); auto s = Singleton::getInstance(); return app.exec(); // After this line executes, destruction of 's' may cause issues with signals/slots system already destroyed by QApplication's destructor. } ``` 以上代码展示了如何正确管理一个简单的单例类,同时也提醒开发者注意析构时机的选择以免造成不必要的麻烦。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值