找回密码
 立即注册
收起左侧

C++老鸟日记033 static两种基本含义

3
回复
5327
查看
[复制链接]
累计签到:41 天
连续签到:1 天
来源: 原创 2018-9-26 16:05:35 显示全部楼层 |阅读模式

马上注册,查看详细内容!注册请先查看:注册须知

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 baizy77 于 2018-10-1 21:01 编辑

版权声明
---------------------------------------------------------------------------------------------------------------------
该文章原创于Qter开源社区(www.qter.org
作者: 女儿叫老白 (白振勇)
转载请注明出处!
---------------------------------------------------------------------------------------------------------------------
本套课程属于:《C++跨平台开发干货》系列课程。
-----------------------------------------------------------------------------


引言:
----------------------------------------------------------------------------
       static关键字用来定义变量的作用域或者生存期。一个 extern变量则是全局可见的,而static则表明该变量仅在局部可见。static变量仅初始化一次,那么它在内存的什么位置呢?在堆还是栈上呢?今天,我们就来讨论一下static关键字。

正文:
----------------------------------------------------------------------------
       在C/C++中,static有两个基本含义:
第一个基本含义是指static变量定义在静态存储区,也就是static变量既不在堆上也不在栈上,这是编译器专门分配的一块特殊存储区。
第二个基本含义指static变量是局部可见的。它仅在定义它的编译单元中可见。如果定义在函数体内,则仅在函数体内可见,如果定义在类内,则仅在类的内部可见,如果定义在文件中(函数体的外部、类的外部),那么仅在该文件内可见。
       static变量仅在函数调用处初始化一次,而且是常驻内存的。因此,当我们希望一个变量在程序的整个生命周期内存在,但是仅在局部可见时,就用到static关键字了。请注意,我们讲的是函数调用处,也就是说,如果一个static变量被定义在函数func()中:
       int func() {
              static int s_intValue = 0;
              s_intValue ++;
              return s_intValue;
}
       但是,如果上面代码中的func()函数在程序整个生命周期内没有被调用过,那么该s_intValue的static变量也就从来没有在内存中存在过,更没有初始化过。
       实际上,在多线程环境中,编程将变得复杂起来。我们为了保证程序在多线程时可以正常运行,通常会使用数据锁来保护变量。但是如果把这个变量定义在静态对象的类内部,就可能出现问题。比如:
       // class.h
       CMutex  g_mtx;//CMutex为某种数据锁。比如QMutex。此处我们不做过多讨论。
class CMyClass {
              static CMyClass& instance() {
                     g_mtx.lock();
                     static CMyClass s_staticObj;
g_mtx.unlock();
                     return  s_staticObj;
}
       public:
              ~CMyClass(){}
       private:
              CMyClass(){}         
};
       比如,上述代码中是一个单体类的简单实现,在instance()接口中,如果不使用全局锁进行保护,那么在多线程环境下(低版本的编译器中),有可能造成该接口多次重入时s_staticObj变量多次初始化的现象,这是非常奇怪的,因为按照static关键字的语法,使用static定义的变量应该有且仅有一次初始化过程,但是小编却经历过存在多次初始化过程的static变量。这很有可能跟编译器及其特定版本有关。
      静态对象的析构函数一般是在main()函数退出或者exit()被调用时才调用,因此在静态对象的析构函数中调用exit()将导致死循环。这点是我们需要注意的。静态对象的析构顺序是按它们构造的顺序相反进行的,这点可以由编译器保证。
       本文开头提到过,extern变量可以被全局作用域访问,如果希望一个变量仅在某个文件内可见,就可以使用static关键字,它可以保证该变量仅在该文件内可见。

结语:
----------------------------------------------------------------------------
       static关键字在定义常驻内存的变量时经常会被使用,它也被用来实现单体类定义。当然,现在有很多第三方库提供了单体类模板的支持,已经使编程变得简单多了。希望static在大家的软件开发过程中发挥更大的作用。
       如果您喜欢本文欢迎转发。也可关注本人的微信公众号。

参考资料
----------------------------------------------------------------------------
《C++编程思想》两卷合订本中文版(10.1章节),(美) BruceEckel  Chuck Allison著


回复

使用道具 举报

累计签到:50 天
连续签到:1 天
2018-9-27 16:38:15 显示全部楼层
你好 :


因此在静态对象的析构函数中调用exit()将导致死循环。   怎么产生的死循环,     重理论上来说都析构两次吧。  出现段错误, 我是这样理解的,不知道老师是如何的?
还有一个问题 : 如果定义在函数体内,则仅在函数体内可见,如果定义在类内,则仅在类的内部可见,如果定义在文件中(函数体的外部、类的外部),那么仅在该文件内可见。      
static 如果定义到函数中,  应该在该函数可以修改, 本文件可读。 ???
回复 支持 反对

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-27 17:30:55 显示全部楼层

问题1,exit()会导致static对象的析构函数被调用,而如果我们在static的析构函数中调用exit(),将无限循环下去。
问题2,没看明白啥意思。函数内定义的static,在函数外文件内不可访问。
回复 支持 反对

使用道具 举报

累计签到:50 天
连续签到:1 天
2018-9-28 11:41:43 显示全部楼层
通过程序验证确实是老师说的那样,  无比激动。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了