美文网首页
浅谈全局变量与局部静态对象

浅谈全局变量与局部静态对象

作者: 404Not_Found | 来源:发表于2021-09-13 23:10 被阅读0次
    • 作者: 雪山肥鱼
    • 时间:20210914 22:47
    • 目的: 临时对象,全局对象,局部静态对象

    临时对象

    void fun()
        {
            {
                //调用析构
                A obja;
            }
            int b = 0; 
            b = 10;
        }
    

    临时对象出了作用域就会调析构。
    所以插入临时对象的时机,会影响开销

        /*
                A obja 放在 if之后 比放在 if 之前会高效一些。
                int i ;
                int j ;
                ...
                if(1)
                {
                    return
                }
                A obja;
                obja.m_i = 10;
            */
    

    这种插在if之前会比差在之后多一点开销。插在前面,无论如何都会多一次构造和析构。

    return 与 临时对象的析构

    void fun1()
        {
            A obja;     
            int mytest = 1;
            if (mytest == 0) 
            {
                return;
            }
            int b = 0;
            b = 10;
            return;
        }
    

    两个return的地方都会准备了析构函数。起始还是那句话,只要除了作用域,编译器就会在此处插入析构

    全局对象

    namespace sp2
    {
        class A
        {
        public:
            A()
            {
                cout << "A::A()" << endl;
            }
            ~A()
            {
                cout << "A::~A()" << endl;
            }
            int m_i;
        };
        A g_aobj;
    }
    

    全局对象在数据段,如果未被初始化,则全局对象内存全部清0 包括其内部的m_i = 0.
    全局变量的构造函数发生在main函数之前,不管有没有调用到,都会把空间分配出来。不像临时变量,调到你才会被分配。
    如果不重新生成项目,则全局变量的地址永远不会发生改变。

    局部静态对象的构造

    测试代码

    namespace sp1
    {
        class A
        {
        public:
            A()
            {
                cout << "A::A()" << endl;
            }
            ~A()
            {
                cout << "A::A()" << endl;
            }
            int m_i;
    
        };
        void myfun()
        {
            static A m_obj1;
            static A m_obj2;
            printf("m_obj1 address:%p\n", &m_obj1);
            printf("m_obj2 address:%p\n", &m_obj2);
        }
    
        /*
        void func()
        {
            
        }
        */
    
        void func()
        {
            //只构造一次
            myfun();
            myfun();
        }
    
    }
    

    放开空函数 func() 进行测试得到结论:

    1. 与全局static不同,不主动调用局部静态变量,则不会对其进行构造
    2. 如果调用,则在编译期间就确定了变量地址
    3. 如果未初始化,则局部静态对象的内存内容全部被初始化为0
    4. 局部静态对象只会构造一次。

    为什么只会构造一次

    对于静态对象,在其构造的时候,对其内存增加标识。以vs2017 为例。


    汇编查看static.PNG

    代码走到static A obj 后,会走到一行 initial thread_header 的标记,跳到08D1109h 后,查看均为0 .

    汇编查看2.PNG

    随后代码走完 init_thread_footer 后08D11CCh 后跟的4个字节 置换成了01000080h。

    这就是标记,如果编译器下次再走过来,发现这里有此标记,则不会再进行构造了。所以局部静态对象只会被构造一次。

    局部静态变量的析构

    放在了 main 函数执行之后的 _aexit();
    相当于做个钩子。


    aexit析构.PNG aexit析构2.PNG

    局部静态对象数组

        const  A & myfunc()
        {
            static A obj[5];
        }
    

    数组内存应该是 连续的 已经分配了, 无论是编译的适合就分配好在bss段,还是 后续分配的空间,无所谓了,记得在bss里分配即可.
    但是太大也不会分配。感觉类似 demangding page.

    相关文章

      网友评论

          本文标题:浅谈全局变量与局部静态对象

          本文链接:https://www.haomeiwen.com/subject/vavhgltx.html