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");
}
non-local static 变量初始化顺序不确定,带来的问题的更多相关文章
- 调整static变量初始化顺序的一个办法
// wrap the LaunchDir variable in a function to work around static/global initialization order stati ...
- 【细说Java】Java变量初始化顺序
Java的变量初始化顺序,对这里一直似懂非懂,面试的时候也经常被问到,但答的一直不好,现在整理记录一下,以后忘记了可以来看看. 程序分为两个部分,第一个部分不考虑继承,第二个部分考虑继承: (1)不考 ...
- c++ 类与函数中static变量初始化问题(转)
首先static变量只有一次初始化,不管在类中还是在函数中..有这样一个函数: void Foo() { ; // initialize std::cout << a; a++; } 里的 ...
- C++成员变量初始化顺序问题
由于面试题中,考官出了一道简单的程序输出结果值的题:如下, class A { private: int n1; int n2; public: A():n2(0),n1(n2+2){} void P ...
- java变量初始化顺序
第一次实例化一个类时,初始化优先顺序为: 1.父类中的静态成员变量和静态代码块初始化 2.本类中的静态成员变量和静态代码块初始化 3.父类中的实例成员初始化 4.父类中的构造方法 5.本类中的实例成员 ...
- Java静态方法,静态变量,初始化顺序
1. 静态方法: 成员变量分为实例变量和静态变量.其中实例变量属于某一个具体的实例,必须在类实例化后才真正存在,不同的对象拥有不同的实例变量.而静态变量被该类所有的对象公有(相当于全局变量),不需要实 ...
- Java中类成员变量初始化顺序
一. 定义处默认初始化vs构造函数中初始化 java中类成员变量支持在声明处初始化,也可以在构造函数中初始化,那么这两者有什么区别呢?看下面例子 public class FieldsInit { p ...
- java静态类、静态方法、静态代码块,静态变量及实例方法,实例变量初始化顺序及内存管理,机制
1.当一个类被第一次使用时,它需要被类加载器加载,而加载过程涉及以下两点: (1)在加载一个类时,如果它的父类还未被加载,那么其父类必须先被加载: (2)当类加载到内存之后,按照在代码中的出现顺序执行 ...
- Java类的变量初始化顺序
大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台 ...
随机推荐
- 【Spring Cloud 源码解读】之 【如何配置好OpenFeign的各种超时时间!】
关于Feign的超时详解: 在Spring Cloud微服务架构中,大部分公司都是利用Open Feign进行服务间的调用,而比较简单的业务使用默认配置是不会有多大问题的,但是如果是业务比较复杂,服务 ...
- Python 中 unittest 单元测试框架中需要知识点
现在正在使用 unittest 框架,我们来记录下这个框架的知识点: unittest 框架:我们在写接口用例的时候,会继承 unittest 当中的 TestCase 的类和方法,私有方法除外,来识 ...
- 1054 求平均值 (20 分)C语言
本题的基本要求非常简单:给定 N 个实数,计算它们的平均值.但复杂的是有些输入数据可能是非法的.一个"合法"的输入是 [−1000,1000] 区间内的实数,并且最多精确到小数点后 ...
- JavaScript数据类型 - Symbol
ES5:对象的属性名只能是字符串,当给对象添加新属性时,很容易造成属性名冲突,从而覆盖了原有的属性. ES6:所以ES6中引入了symbol数据类型,他表示独一无二的值,避免了属性名的冲突,此时对象的 ...
- FIND_IN_SET 精确查找
FIND_IN_SET(str,strlist) mysql专为精确匹配字符串而设置的函数 一个字符串列表就是一个由一些被‘,’符号分开的自链组成的字符串 1,2,3,4,5,6,7,8,9: 此函数 ...
- 高效测试框架推荐之Ginkgo
自2015年开始,七牛工效团队一直使用Go语言+Ginkgo的组合来编写自动化测试用例,积累了大约5000+的数量.在使用和维护过程中,我们觉得Ginkgo的很多设计理念和功能非常赞,因此特分享给大家 ...
- 深入理解协程(四):async/await异步爬虫实战
本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...
- Gym - 101982F 扫描线+线段树
题目链接:https://codeforces.com/gym/101982/attachments 要你求覆盖奇数次的矩形面积并,每次更新时减去原先的值即可实现奇数次有效,下推时为保证线段长度不变左 ...
- AVR单片机教程——LCD1602
本文隶属于AVR单片机教程系列. 显示屏 开发板套件里有两块屏幕,大的是LCD(液晶显示),小的是OLED(有机发光二极管).正与你所想的相反,短小精悍的比较贵,而本讲的主题--LCD1602-- ...
- LeetCode 第98题--验证二叉搜索树
1. 题目 2.题目分析与思路 3.代码 1. 题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当 ...