問題
首先考慮一個全局變量的初始化順序問題
在頭文件1中:
extern int b; int a = b + 1;
在頭文件2中:
extern int a; int b = a + 1;源文件中包含了頭文件1和頭文件2,這種情況下a和b可能的值是什么呢?
雖然在開發過程一般不會出現上述這種情況,但是這核心的是一個全局變量初始化順序的問題,這個問題在團隊開發過程可能會碰到。
可以使用static的特性來解決此問題,static關鍵字作用一般有以下幾點:
1. 靜態全局變量,變量在該翻譯單元是可見的,但是在其他翻譯單元中是不可見的(翻譯單元暫時理解為源文件,后文解析)。如下:
//源文件1中 static int n; //源文件2中 extern int n;//這里編譯無錯,但鏈接出錯,因為源文件1中的n是外部不可見的2. 靜態局部變量,變量雖然是一個局部變量,但是它在全局變量區分配內存,該變量在局部可見,並且只初始化一次。
3. 靜態函數,和靜態全局變量一樣,該翻譯單元可見,外部不可見。
4. 類中靜態成員變量,變量需要在類外部聲明,所有類的對象共用一個靜態成員變量。
5. 類中靜態成員函數。
解決方式
Initializer.h中:
#ifndef INITIALIZER_H #define INITIALIZER_H #include <iostream> extern int x; extern int y; class Initializer { static int initCount; public: Initializer() { std::cout << "Initializer()" << std::endl; if (initCount++ == 0) { std::cout << "performint initialization" << std::endl; x = 100; y = 200; } } ~Initializer() { std::cout << "~Initializer()" << std::endl; if (--initCount == 0) { std::cout << "performint cleanup" << std::endl; } } void testFun() { std::cout << "testFun"<< initCount << std::endl; } private: }; static Initializer init; #endif
Initializer.cpp
#include "Initializer.h" int x; int y; int Initializer::initCount;
其他cpp文件只需要包含頭文件即可自動解決x和y的初始化順序問題。
#include "Initializer.h"
在Initializer.h定義了一個靜態全局變量,這個變量在一個翻譯單元是內部可見的,所以Initializer.cpp和所有包含Initializer.h的源文件中都會又有一個init變量,這個變量雖然名稱相同,但是每個翻譯單元的init變量地址是不同的。不理解的話可以考慮下面代碼的輸出:
header.h中:
static int nCount = 1;
fun.cpp中:
#include "header.h" #include <iostream> void fun() { std::cout << "enter fun:" << &nCount << "\t" << nCount << std::endl;nCount++; std::cout << "leave fun:" << &nCount << "\t" << nCount << std::endl;}
main.cpp中:
#include "header.h" #include <iostream> extern void fun(); int main() { std::cout << "enter main:" << &nCount << "\t" << nCount << std::endl;fun(); std::cout << "leave main:" << &nCount << "\t" << nCount << std::endl;return 0; }header.h中定義了一個靜態全局變量,fun.cpp是一個翻譯單元,編譯fun.cpp時,nCount是一個內部可見(fun.cpp內可見)的全局變量。編譯main.cpp時,nCount是一個內部可見(main.cpp內可見)的全局變量,這兩個變量雖然變量名是一樣的,但是地址是完全不同的。
輸出如下: