C++静态类型成员变量的初始化顺序(单例模式)

对编译器来说,静态成员变量的初始化顺序和析构顺序是一个未定义的行为

#include <string>
#include <iostream>
using namespace std;
class Base{
public:static int b;static int a;};
int Base::b = 2;
int Base::a = b + 1;int main()
{Base base;cout <<"Base::a="<< Base::a << endl;cout <<"Base::b="<< Base::b << endl;return 0;
}

请添加图片描述

6 7 18 19 行怎么修改值都一样可见静态类型成员变量的初始化顺序和编译器和有关
如下文所说:https://wenku.baidu.com/view/60a101842b4ac850ad02de80d4d8d15abe2300da.html
理解在⼀个应⽤程序内部,静态变量的构造/析构顺序。其中,对于全局静态变量,视编译器的实现⽽定(⼀种⽅式是根据字
母顺序来决定);对于有依赖关系的,那么视依赖关系⽽定。⽽对于局部静态变量来说,问题就开始复杂了。这也正是本⽂论述的重点。
⾸先,要理解编译器是如何实现局部静态变量的语法特性的。从语法上来看,局部静态变量与全局静态变量最⼤的不同在于构造时机——当
且仅当程序执⾏路径⾸次达到局部静态变量的定义处才出发构造。注意是⾸次。印象中编译器是通过添加⼀个标识变量(当然这个变量⼀定
是全局静态的)来实现的(即每次程序执⾏到时,⾸先检查这个标志变量),如此来确保调⽤时构造且只构造⼀次的特性。那么反过来看局
部静态变量的析构,编译器会维护⼀个析构函数的函数指针栈,⼀旦构造完成,就会把相应的析构函数指针放到这个栈中。当程序结束后,
由编译器⽣成的doexit函数会逐个调⽤这些析构函数,完成进程结束前的扫尾⼯作。基于此,很显然,对于分布在程序各处的静态局部变
量,其构造顺序取决于它们在程序的实际执⾏路径上的先后顺序,⽽析构顺序则正好与之相反。
很简单,不是么?可为什么说是隐藏的坑呢,问题在于:

⼀⽅⾯是因为程序的实际执⾏路径有多个决定因素(例如基于消息驱动模型的程序和多线程程序),有时是不可预知的; 另⼀⽅⾯是因为局部静态变量分布在程序代码各处,彼此直接没有明显的关联,很容易让开发者忽略它们之间的这种关系(这是最坑的地 ⽅)。

既然提出问题,那么就讨论应对之道:
(1)最简单的,避免使⽤局部静态变量,将变量的声明周期控制在开发者⼿中;
(2)如果确有需要,那么尽量确保局部静态变量之间构造和析构是彼此独⽴互不相关的,换句话说,它们可以以任意的顺序被构造和析
构;
设计模式里的单例模式就有静态变量互相引用从而系统奔溃。
测试程序

#include <string>
#include <iostream>
using namespace std;
class Log
{
public:static Log* GetInstance(){static Log oLog;return &oLog;}void Output(string strLog){cout<<strLog<<(*m_pInt)<<endl;}
private:Log():m_pInt(new int(3)){}~Log(){cout<<"~Log"<<endl;delete m_pInt;m_pInt = NULL;}int* m_pInt;
};class Context
{
public:static Context* GetInstance(){static Context oContext;return &oContext;}~Context(){Log::GetInstance()->Output(__FUNCTION__);}void fun(){Log::GetInstance()->Output(__FUNCTION__);}
private:Context(){}Context(const Context& context);
};int main(int argc, char* argv[])
{Context::GetInstance()->fun();return 0;
}

参考博客:https://www.freesion.com/article/7937607333/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/447126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

区块链中密码学与安全技术

区块链的定义 区块链的定义&#xff0c;应当是&#xff1a;区块链是一种按照时间顺序将数据进行分布式存储的块链式数据结构&#xff0c;它利用共识机制进行数据验证&#xff0c;利用密码学进行数据保护和用户安全访问&#xff0c;利用智能合约来操作数据&#xff0c;从而成为…

面经:单例模式

侯捷单例 和剑指不同 &#xfffc; 饿汉式 饿汉式的特点是一开始就加载了&#xff0c;如果说懒汉式是“时间换空间”&#xff0c;那么饿汉式就是“空间换时间”&#xff0c;因为一开始就创建了实例&#xff0c;所以每次用到的之后直接返回就好了。饿汉式有两种常见的写法&…

属性加密技术及基于属性的ABE算法的访问控制技术介绍

属性加密技术 基于身份的加密体制简介 基于身份的加密体制可以看作一种特殊的公钥加密&#xff0c;它有如下特点:系统中用户的公钥可以由任意的字符串组成。这些字符串可以是用户在现实中的身份信息&#xff0c;如:身份证号码、用户姓名、电话号码、Email地址等&#xff0c;因…

基于属性加密的ABE算法的应用场景思考展望

ABE算法先前使用在云计算场景中&#xff0c;和区块链存在交叉应用场景&#xff0c;具体问题体现在 数据的异地存储、云服务器提供商的不可信、管理员能否对自身数据拥有足够的控制能力以及如何保证数据的安全有效共享都是亟需解决的问题。 研究背景&#xff1a; 云计算越来越…

面经:设计模式

什么是接口隔离原则&#xff08;Interface Segregation Principle&#xff09; 定义&#xff1a;客户端不应该依赖它不需要的接口&#xff1b;一个类对另一个类的依赖应该建立在最小的接口上。概括的说就是&#xff1a;建立单一接口&#xff0c;不要建立臃肿庞大的接口。&…

区块链、密码和银行之间的衍生关系

银行场景中密码服务 设置密码 用户在注册的时候&#xff0c;如果使用弱密码&#xff0c;系统会检测出来。我的猜测是将弱密码的hash运算和用户输入的密码hash比对&#xff0c;如果一致&#xff0c;禁止用户注册。 1、不要设置简单密码&#xff0c;您设置的密码必须符合中信银…

AIgorand区块链中VRF随机函数的应用

VRF&#xff08;Verifiable Random Function&#xff09; 可验证随机函数可以看作是一个随机预言机&#xff0c;即可以通过任意的一个输入&#xff0c;获得一个随机数输出&#xff1a;输出的结果&#xff08;Output&#xff09;是一个随机数&#xff0c;其数值会均匀分布在值域…

C++学习笔记 简单部分

C 数据类型 使用变量来存储各种信息&#xff0c;变量保留的是它所存储的值的内存位置。这意味着&#xff0c;当创建一个变量时&#xff0c;就会在内存中保留一些空间。这段内存空间可以用于存储各种数据类型&#xff08;比如字符型、宽字符型、整型、浮点型、双浮点型、布尔型…

terminate called after throwing an instance of ‘std::logic_error‘ what(): basic_string::_M_constr

terminate called after throwing an instance of ‘std::logic_error’ what(): basic_string::_M_construct null not valid 用0初始化字符串 编译不报错

密钥协商(密钥交换)机制的讲解

国标文件涉及密钥协商算法的函数 生成密钥协商参数并输出计算会话密钥产生协商数据并且计算会话密钥 密钥协商&#xff08;交换&#xff09;算法及其原理 密钥交换/协商目的 “密钥协商机制”是&#xff1a;&#xff08;在身份认证的前提下&#xff09;规避【偷窥】的风险。…

基于ECC算法的秘钥协商

基于ECC算法的衍生算法 ECDH(ECCDH)RSAECDHE(ECCDHE) ECDH密钥协商&#xff08;ECCDH&#xff09; 椭圆曲线密码学是属于非对称密码学的&#xff0c;其私钥的计算公式如下&#xff1a; 私钥是一个随机数d&#xff0c;取值范围在1……n-1,其中n是子群的阶公钥是点HdG&#xff…

C++11 多线程相关知识的学习

C多线程类Thread&#xff08;C11&#xff09; C11中std命名空间将Boost库中的Thread加入&#xff0c;Boost的多线程从准标准变为标准&#xff0c;这里将其用法整理复习&#xff0c;以demo的形式复习&#xff0c;还是喜欢看我自己写的东西&#xff0c;符合我的个人逻辑头文件为…

C++11 explicit关键字的作用

explicit 在C中&#xff0c;explicit关键字用来修饰类的构造函数&#xff0c;被修饰的构造函数的类&#xff0c;不能发生相应的隐式类型转换&#xff0c;只能以显示的方式进行类型转换。因为无参构造函数和多参构造函数本身就是显示调用的。再加上explicit关键字也没有什么意义…

C++11学习 virtual(虚函数)的用法

Virtual虚函数 在面向对象的C语言中&#xff0c;虚函数&#xff08;virtual function&#xff09;是一个非常重要的概念。因为它充分体现了面向对象思想中的继承和多态性这两大特性&#xff0c;在C语言里应用极广。多态性&#xff1a;其含义就是多种形式&#xff1b;将具有继承…

c++ const

函数名称不单单是函数名 const 补充内容 还有 const 参数类型 函数后头const 只能在成员函数如果const对象 但是我没通过const成员函数 就会报错

手撕源码 alloc

怎么有效的手撕代码呢&#xff1f; gnu gcc 2.9 的 内存池 把代码跑起来把代码一个片段拿出来使用画出代码运行的流程图一行一行的搬运在看源码的情况下写出类似的demo 第三步&#xff1a; 第五步: // 这个头文件包含一个模板类 allocator&#xff0c;用于管理内存的分配、…

针对Algorand所使用的密码相关技术细节进行介绍

关键概念 VRF: 可验证随机函数。简单来说是&#xff1a;vrf,Proof VRF(sk,seed)&#xff0c;sk为私钥&#xff0c;seed为随机种子&#xff1b;通过Verify(proof,pk,seed)验证vrf的合法性。cryptographic sorition: 根据用户本轮的VRF值&#xff0c;自身的权重以及公开的区块链…

对于Algorand的介绍

介绍 Algorand具有能耗低、效率高、民主化、分叉概率极低、可拓展性好等优点&#xff0c;旨在解决现有区块链项目存在的“不可能三角”&#xff08;高度可扩展的、安全的、去中心化&#xff09;问题。Algorand由MIT教授、图灵奖得主Silvio Micali发起&#xff0c;拥有MIT区块链…

C++学习 高级编程

C 文件和流 到目前为止&#xff0c;目前使用最为广泛的是 iostream 标准库&#xff0c;它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。以下将介绍从文件读取流和向文件写入流。这就需要用到 C 中另一个标准库 fstream&#xff0c;它定义了三个新的数…