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;从而成为…

面经:服务器相关

阻塞IO 当你去读一个阻塞的文件描述符时&#xff0c;如果在该文件描述符上没有数据可读&#xff0c;那么它会一直阻塞(通俗一点就是一直卡在调用函数那里)&#xff0c;直到有数据可读。当你去写一个阻塞的文件描述符时&#xff0c;如果在该文件描述符上没有空间(通常是缓冲区)…

如何用区块链保障数据安全和承载数据确权

区块链可以确保数据安全&#xff0c;体现在那些方面呢&#xff1f; 主要是两个维度&#xff0c;一是数据的不可篡改性&#xff1b;另外一个就是数据的隐私安全性。区块链技术本身并不解决任何的安全问题&#xff0c;因此需要搭配安全技术一起使用&#xff0c;比如非对称加密、…

面经:单例模式

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

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

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

面经:http协议

总结HTTPS传输过程 客户端先从服务器获取到证书&#xff0c;证书中包含公钥 客户端将证书进行校验 客户端生成一个对称密钥&#xff0c;用证书中的公钥进行加密&#xff0c;发送给服务器 服务器得到这个请求后用私钥进行解密&#xff0c;得到该密钥 客户端以后发出后续的请求&…

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

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

面经:设计模式

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

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

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

面经:多线程 线程池

使用线程池 当进程被初始化后&#xff0c;主线程就被创建了。对于绝大多数的应用程序来说&#xff0c;通常仅要求有一个主线程&#xff0c;但也可以在进程内创建多个顺序执行流&#xff0c;这些顺序执行流就是线程&#xff0c;每一个线程都是独立的。 线程是进程的组成部分&am…

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

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

AIgorand的相关学习参考链接

相关具体的开发者与SDK链接如下&#xff1a; GoSDKJavaScript SDK 网页链接 测试网申请链接Github存储库链接开发者网址AIgorand官网Telegram电报群综合白皮书MediumNaver Blog领英Linkedin区块链浏览器INC公示钱包地址基金会公示钱包地址Telegram电报群官方 Github地址 相关…

操作系统 内核栈

视频哈工大李治军老师&#xff1a;https://www.bilibili.com/video/BV1d4411v7u7?p12 参考文档&#xff1a;https://blog.csdn.net/SakuraA6/article/details/108810916 学长在我大一推荐我看&#xff0c;p12和p13的内容真的有那么难吗&#xff0c;现在已经是我看的第三遍了还…

区块链技术指南 序章理解感悟

序二 误区一&#xff1a; 区块链是一种颠覆性的新技术。区块链不是一个新的技术&#xff0c;而是一个新的技术的组合。其关键的技术&#xff0c;包括P2P动态组网、基于密码学的共享账本、共识机制&#xff08;拜占庭将军问题&#xff0c;分布式场景下的一致性问题&#xff09…

面经:红黑树 B树 B+树 哈希表

1.对于插入&#xff0c;删除&#xff0c;查找 以及 输出有序序列 这几个操作&#xff0c;红黑树也可以完成&#xff0c;时间复杂度 与 用跳表实现是相同的。 但是&#xff0c;对于按照区间查找数据这个操作&#xff08;比如 [20,300]&#xff09;,红黑树的效率没有跳表高&#…

回溯法和dfs的区别

值得注意&#xff0c;回溯法以深度优先搜索的方式搜索解空间&#xff0c;并且在搜索过程中用剪枝函数避免无效搜索。那为何 回溯算法 深度优先搜索 剪枝函数这一说法没有错&#xff1f; 因为树是特殊的图。简单来说&#xff0c;树是广义的图。再简单来说&#xff0c;树是图。…

C++学习笔记 简单部分

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

Redis kqeue相关源码

mask 或delmask &#xff1a;添加或者删除的事件类型&#xff0c;AE_NONE表示没有任何事件&#xff1b;AE_READABLE表示可读事件&#xff1b;AE_WRITABLE表示可写事件&#xff1b; 如aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); static int aeApiAddEv…

C++学习笔记章节中 面向对象详解

C 类&对象 C类定义 本质上是一个数据类型的蓝图&#xff0c;定义了类的对象包含的信息&#xff0c;以及可以在这个类对象上执行哪些操作。类的定义是以class开头&#xff0c;后面接类的名称。类的主体是包含在一个花括号中&#xff0c;类的定义之后&#xff0c;必须跟着一…

Mac 破解软件打不开没有权限

Mac 破解软件打不开没有权限 sudo codesign -fs - /Applications/CleanMyMac\ X.app文件损坏 xxx sudo xattr -r -d /Applications/MarginNote\ 3.app sudo xattr -r -d com.apple.quarantine xxxx sudo codesign --force --deep --sign - /Applications/MarginNote\ 3\…