所谓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");
}

non-local static 变量初始化顺序不确定,带来的问题的更多相关文章

  1. 调整static变量初始化顺序的一个办法

    // wrap the LaunchDir variable in a function to work around static/global initialization order stati ...

  2. 【细说Java】Java变量初始化顺序

    Java的变量初始化顺序,对这里一直似懂非懂,面试的时候也经常被问到,但答的一直不好,现在整理记录一下,以后忘记了可以来看看. 程序分为两个部分,第一个部分不考虑继承,第二个部分考虑继承: (1)不考 ...

  3. c++ 类与函数中static变量初始化问题(转)

    首先static变量只有一次初始化,不管在类中还是在函数中..有这样一个函数: void Foo() { ; // initialize std::cout << a; a++; } 里的 ...

  4. C++成员变量初始化顺序问题

    由于面试题中,考官出了一道简单的程序输出结果值的题:如下, class A { private: int n1; int n2; public: A():n2(0),n1(n2+2){} void P ...

  5. java变量初始化顺序

    第一次实例化一个类时,初始化优先顺序为: 1.父类中的静态成员变量和静态代码块初始化 2.本类中的静态成员变量和静态代码块初始化 3.父类中的实例成员初始化 4.父类中的构造方法 5.本类中的实例成员 ...

  6. Java静态方法,静态变量,初始化顺序

    1. 静态方法: 成员变量分为实例变量和静态变量.其中实例变量属于某一个具体的实例,必须在类实例化后才真正存在,不同的对象拥有不同的实例变量.而静态变量被该类所有的对象公有(相当于全局变量),不需要实 ...

  7. Java中类成员变量初始化顺序

    一. 定义处默认初始化vs构造函数中初始化 java中类成员变量支持在声明处初始化,也可以在构造函数中初始化,那么这两者有什么区别呢?看下面例子 public class FieldsInit { p ...

  8. java静态类、静态方法、静态代码块,静态变量及实例方法,实例变量初始化顺序及内存管理,机制

    1.当一个类被第一次使用时,它需要被类加载器加载,而加载过程涉及以下两点: (1)在加载一个类时,如果它的父类还未被加载,那么其父类必须先被加载: (2)当类加载到内存之后,按照在代码中的出现顺序执行 ...

  9. Java类的变量初始化顺序

    大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台 ...

随机推荐

  1. 三分钟学会使用Docker部署.NET Core

    大概快有一年的时间没有碰过docker了,理由很简单,基本上都是在IIS上部署,看到很多大佬都开始Devops持续化集成了,但相对来说成本会更高,但对于大型团队来说还是不错的,这不?不想被大伙甩下,哈 ...

  2. C / C++ 保留小数函数(setprecision(n)的一些用法总结)

    从C语言开始正式学习C++,但是一上来输出位数就懵了,查资料才知道C++需要使用 “ setprecision  ”函数.自己总结一下. 首先说C++代码 #include <iomanip&g ...

  3. 啊哈!C语言课后参考答案上

    最近看到一本好评量很高的的C语言入门书,课本真的很好,入门的话.专业性没有那么强,但入门足够了!!好评!看着看着就想把这本书的题课后习题都写出来,最后就有了这个小结.可能有的不是最好,不那么专业,但主 ...

  4. overflow:hidden的使用

    (1)overflow:hidden可以用来隐藏溢出的文本内容 给定内容的大小(宽高)超出后自动隐藏 <body>     <div class="box"> ...

  5. Go语言教程之结构体

    Hello,大家好,我是小栈君,最近因为工作的事情延误了一点分享的进度,但是我会尽量抽时间分享关于IT干货知识,还希望大家能够持续关注"IT干货栈"哦. 闲话不多说,今天给大家继续 ...

  6. 常用Java静态代码分析工具的分析与比较

    给国产静态代码检测工具Pinpoint打Call! 简介 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了4种现有的主流Java静态代码分析工具 (Checkstyle,FindBugs ...

  7. IPython的介绍与使用

    1.IPython简介 ipython是一个python的交互式shell,比默认的python shell好用得多,支持变量自动补全,自动缩进,支持bash shell命令,内置了许多很有用的功能和 ...

  8. 【一起学源码-微服务】Hystrix 源码二:Hystrix核心流程:Hystix非降级逻辑流程梳理

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一讲我们讲了配置了feign.hystrix.enabl ...

  9. Java操作Jxl实现数据交互。三部曲——《第三篇》

    Java操作Jxl实现上传文本文件实现转PDF格式在线预览. 本文实现背景Web项目:前台用的框架是Easyui+Bootstrap结合使用,需要引入相应的Js.Css文件.页面:Jsp.拦截请求:S ...

  10. HTTP1.1

    读了一本图解http,总结一下子. 1 .重要的头部   1.TCP/IP 通信传输流 五层模型 先盗个图,重点说明每过一层都会加个头,头很重要啊!其中https 就是在传输层搞事,把本来明文的数据包 ...