C/C++ 中的 static

一 、函数内部的静态变量

在函数体内定义一个局部变量时,编译器在每次函数调用时,使堆栈的指针向下移动,为这些局部变量分配内存。

定义一个全局变量将不仅仅只受这个函数控制。

在C/C++函数内部定义的 static 对象,将存储在程序的静态数据区(static data area)中。

char * c = "abc" 这样的赋值会得到一个警告:不建议从字符常量到 char * 的转换,最好在前面加上 const

  1 #include <iostream>
  2 using namespace std;
  3
  4 char oneChar(const char * charArray = 0){
  5         static const char * s;
  6         if(charArray){
  7                 s = charArray;
  8                 return *s;
  9         }else{
 10                 cout <<"un initialized\n";
 11         }
 12         if( * s == '\0'){
 13                 return 0;
 14         }
 15         return *s++;
 16 }
 17
 18 char * a = "abcdefghijklmnopqrstuvwxyz";
 19
 20 int main(){
 21         oneChar(a);
 22         char c;
 23         while((c = oneChar()) != 0)
 24                 cout << c <<endl;
 25         return 0;
 26 }

从上例可以看到 static const char * s 在每次函数调用时都保留了值。

可以看出来,在上面的函数中容易产生多线程的问题;在设计包含静态变量的函数时,应该记住多线程的问题。


二、静态对象的析构函数

静态对象的析构函数,在程序从main() 中退出时,或者标准C库的 exit()被调用时才被调用。(注意:使用abor() 来退出程序,静态对象的析构函数并不会调用)

如果一个包含局部静态对象的函数从未被调用,那么这个对象的构造函数也不会被调用。

同普通对象的销毁一样,静态对象的销毁也是按照与初始化相反的顺序进行的。

  2 #include <fstream>
  3 using namespace std;
  4
  5 ofstream out("statdest.out");
  6
  7 class Obj{
  8         char c;
  9 public:
 10         Obj(char cc):c(cc){
 11                 out<<"Obj::Obj() for "<<c<<endl;
 12         }
 13         ~Obj(){
 14                 out<<"Obj::~Obj() for "<<c<<endl;
 15         }
 16 };
 17
 18 Obj a('a');
 19
 20 void f(){
 21         static Obj b('b');
 22 }
 23
 24 void g(){
 25         static Obj c('c');
 26 }
 27
 28 int main(){
 29         out <<"inside main()"<<endl;
 30         f();
 31         out <<"leaving main()"<<endl;
 32
 33         return 0;
 34 }

注意跟踪文件ofstream 的对象out 也是一个静态对象。

在C++ 中,全局静态对象的构造函数是在main()之前调用的,这样就有了一个在进入main() 之前执行一段代码的方法。

三、变量可见性

所有的全局对象都是隐含为静态存储的。

       int a = 100;

        则 a 被存储在程序的静态数据区,在进入main() 之前,a 已经初始化了。另外,a 对所有的编译单元都是全局可见的。用可见性术语来说,static(只在翻译单元内可见),extern 则明确声明对所有翻译单元都可见。

所以上面的定义和 extern int a = 0 是一样的

但如果这样定义:

static int a = 0  只是改变了a 的可见性,只在本翻译单元内,有时叫文件静态(file static),但并没有改变存储类型—— 仍然驻留在静态数据区,而不管是static 还是 extern

在局部变量中,就总是内部链接了,extern 的修饰没有意义;使用 static 时只会改变变量的存储类型。


四、定义静态数据成员的存储

        因为类的静态数据成员有着单一的存储空间,所有必须在一个单独的地方定义,编译器不会分配存储空间,如果一个静态数据成员被声明但没有定义,则连接器会报告错误。

定义必须出现在类的外部(不允许内联),而且只能定义一次。

(1)这些变量唯一合法的初始化地方就是在定义时

(2)这些变量只能够被定义一次

以上两点来保证变量只被创建者所控制。

 

静态成员函数:

为类的全体对象服务。 可以用普通的方法调用静态成员函数,用“ .” 或者“->” 把它和一个对象相联系。一个更典型的方法是自我调用。

静态成员函数不能访问一般的数据成员,而只能访问静态的数据成员。原因在于:对象的地址(this)是被隐式传递到调用函数的;但static 函数没有this,因此无法访问一般成员。静态函数在速度上比全局函数有少许增长,不仅没有传递this所需要的额外开销,而且还有使得函数在类内的好处。

 

Static initialization dependency:

对于作用域为多个翻译单元的静态对象来说,不能保证初始化顺序,这可能会导致一些问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值