所谓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. Tomcat启动失败原因

    Tomcat启动失败原因 一.Tomcat启动时,要求被加载的项目必须拥有独立路径名称 发布的两个工程具有相同路径名称,这是不允许. 二.8080端口号已经被占用了 启动失败原因,就是8085端口上, ...

  2. Http请求头安全策略

    今天在网上浪了许久,只是为了找一个很简单的配置,却奈何怎么都找不到. 好不容易找到了,我觉得还是记录下来的好,或许省得许多人像我一样浪费时间. 1.X-Frame-Options 如果网站可以嵌入到I ...

  3. 洛谷P3413 SAC#1 - 萌数 题解 数位DP

    题目链接:https://www.luogu.com.cn/problem/P3413 题目大意: 定义萌数指:满足"存在长度至少为2的回文子串"的数. 求区间 \([L,R]\) ...

  4. [推荐]icheck-bootstrap(漂亮的ckeckbox/radiobox)

    适用于Twitter Bootstrap框架的纯CSS样式的复选框/单选框按钮的插件. GitHub:https://github.com/bantikyan/icheck-bootstrap 如果你 ...

  5. 关于Springboot找不到mapper.xml问题

    今天在写springboot项目时报错org.apache.ibatis.binding.BindingException: Invalid bound statement (not found),找 ...

  6. struts2 convention插件

    1.struts2自2.1以后推荐使用Convention Plugin支持struts零配置支持(引入jar:struts2-convention-plugin-2.x.x.jar)①convent ...

  7. 2019 牛客国庆集训day1 2019 点分治

    题目链接:https://ac.nowcoder.com/acm/contest/1099/I 点分治,计算路径数的时候,先将每个点到根的距离模2019,计算的时候就可以O(n)求出数目,对于模201 ...

  8. Xcode10:library not found for -lstdc++.6.0.9 临时解决

    1.https://pan.baidu.com/s/1IkbZb6qaxgvghP1HEFQa6w?errno=0&errmsg=Auth%20Login%20Sucess&& ...

  9. CBV 序列化

    一.模型表 from django.db import models # Create your models here. class Publish(models.Model): name = mo ...

  10. Java入门 - 语言基础 - 16.数组

    原文地址:http://www.work100.net/training/java-array.html 更多教程:光束云 - 免费课程 数组 序号 文内章节 视频 1 概述 2 声明数组变量 3 创 ...