non-local static 变量初始化顺序不确定,带来的问题
所谓static对象,其寿命从被构造出来直到程序结束为止,因此stack和heap-based对象都被排除。这种对象包括global对象、定义于namespace作用域内的对象,classes内、在函数内、以及在file作用域内被声明为static的对象。函数内的static对象称为local static对象(因为它们对函数而言是local),其他static对象成为non-local static对象,在程序结束时static对象会被自动销毁,也就是他们的析构函数会在main()结束时被调用
c++对“定义于不同的编译单元内的non-local static对象”的初始化次序并无明确定义。
为了更清晰的理解上述文字,特意写了一个错误的实例,代码如下:
//a1.cpp #include <fstream> #include <iostream> #include "a3.cpp" using namespace std; Write a; int main() { system("pause"); return 0; } //a2.cpp #include <fstream> using namespace std; extern ofstream out("a6.txt"); //a3.cpp #include <fstream> using namespace std; extern ofstream out; class Write { public: Write() { out<<"a4.txt"; } };
上述代码,a2.cpp中,定义了全局变量 out,a3.cpp中定义了一个类 Write,它的构造函数初始化依赖于 out,因为2个文件的便宜顺序是不确定的,所以,很有可能 当Write()调用的时候,out全局变量并没有被初始化,造成程序错误。
案例2:
先上代码:
//FileSystem.h #include <iostream> class FileSystem { public: FileSystem(int a):num(a) { } std::size_t numDisks() const; private: int num; }; //FileSystem.cpp #include "FileSystem.h" std::size_t FileSystem::numDisks() const { return num; } //Directory.h #include <iostream> #include "FileSystem.h" class Directory { public: Directory(); int display(); private: int a; }; //Directory.cpp #include "Directory.h" extern FileSystem tfs; Directory::Directory() { std::size_t disks = tfs.numDisks(); a = disks; } int Directory::display() { return a; } Directory a; //Y.cpp #include "FileSystem.h" extern FileSystem tfs(10); //X.cpp #include "Directory.h" #include <iostream> using namespace std; extern Directory a; int main() { cout<<a.display()<<endl; system("pause"); }
代码中 Directory对象的初始化依赖于 全局对象FileSystem tfs,因为C++“对定义于不同的编译单元内的non-local static对象”的初始化相对次序并没有明确定义,所以很有可能在 Y.cpp里的变量tfs初始化之前,先初始化 Directory.cpp里的对象a,则a就得不到我们想要的值。
因为C++保证,函数内的local static对象会在“该函数被调用期间”“首次遇到该对象的定义式”时被初始化,所以代码修改如下:
//FileSystem.h #include <iostream> class FileSystem { public: FileSystem(int a):num(a) { } std::size_t numDisks() const; private: int num; }; //FileSystem.cpp #include "FileSystem.h" std::size_t FileSystem::numDisks() const { return num; } //Directory.h #include <iostream> #include "FileSystem.h" class Directory { public: Directory(); int display(); private: int a; }; //Directory.cpp #include "Directory.h" extern FileSystem& tfs(); Directory::Directory() { std::size_t disks = tfs().numDisks(); //tfs()函数返回一个FileSystem& 对象 a = disks; } int Directory::display() { return a; } Directory& tempDir() { static Directory td; return td; } //Y.cpp #include "FileSystem.h" FileSystem& tfs() { static FileSystem fs(10); //在一个函数里,返回静态对象 return fs; } //X.cpp #include "Directory.h" #include <iostream> using namespace std; extern Directory& tempDir(); Directory a=tempDir(); int main() { cout<<a.display()<<endl; system("pause"); }
Keep it simple!