美文网首页
栈上的对象你以为是真的“自动释放”的吗

栈上的对象你以为是真的“自动释放”的吗

作者: xiaoliang1 | 来源:发表于2020-06-28 16:38 被阅读0次

    每次都说栈上的对象是自动释放的。其实你很不明白为什么这么神奇,当你问时,别人还牛逼哄哄的说,哪有那么为什么,记住自动释放释放就行了。这无疑上学时“背课文”。问也不能问。还会遭到训斥,这是让人不能接受的时,你不能提出你的疑问。
    今天就告诉你,其实很简单,就是出栈入栈导致的,分布在栈上的对象,在函数执行完毕。栈会恢复已经开辟的栈空间,所以你在反汇编时经常看到函数开头

    sub         esp,0E8h
    

    而在结尾时:

    add         esp,0F4h  
    

    (当然还有一些出栈,恢复上一个函数的参数等等一些环境)
    这样这个函数执行完毕时,这个栈上的对象可能还在内存中,但当进行其他函数调用,或者其他操作时,这个对象的数据就会被覆盖掉。
    所以,你就理算当然以为的“自动释放”,不用管理.
    那你可能会说哪有这么简单,他会调用一些析构函数或者销毁函数。是自动释放时调用的。
    其实不是这样的,因为调用这是编译器的做的,你看着表面没有调用析构函数或者销毁函数。这都是编译器帮你写了汇编。来通知你,释放前的通知,你可以做一些事,释放这个对象销毁前,要销毁的堆上数据。
    C++这个语言都是站编译器的角度看问题的。底层没什么数据结构和很牛逼的设计来支持,所以只能静态语言了。只能靠编译器隐式帮你做一些操作。
    下面用代码+汇编代码来看来:

    void test3() {
    
        vector<int>p1;
        p1.push_back(1);
    
    }
    

    C++代码就这么简单,p1会在这个函数执行完时,调用vector<int,std::allocator<int> >::~vector<int,std::allocator<int> >这个析构函数,返回代码:

    void test3() {
    00CA8E60  push        ebp  
    00CA8E61  mov         ebp,esp  
    00CA8E63  push        0FFFFFFFFh  
    00CA8E65  push        0CB196Dh  
    00CA8E6A  mov         eax,dword ptr fs:[00000000h]  
    00CA8E70  push        eax  
    00CA8E71  sub         esp,0E8h  
    00CA8E77  push        ebx  
    00CA8E78  push        esi  
    00CA8E79  push        edi  
    00CA8E7A  lea         edi,[ebp-0F4h]  
    00CA8E80  mov         ecx,3Ah  
    00CA8E85  mov         eax,0CCCCCCCCh  
    00CA8E8A  rep stos    dword ptr es:[edi]  
    00CA8E8C  mov         eax,dword ptr [__security_cookie (0CB8008h)]  
    00CA8E91  xor         eax,ebp  
    00CA8E93  mov         dword ptr [ebp-10h],eax  
    00CA8E96  push        eax  
    00CA8E97  lea         eax,[ebp-0Ch]  
    00CA8E9A  mov         dword ptr fs:[00000000h],eax  
    00CA8EA0  mov         ecx,offset _5BA660AA_ConsoleApplication16@cpp (0CBA028h)  
    00CA8EA5  call        @__CheckForDebuggerJustMyCode@4 (0CA14B5h)  
    
        vector<int>p1;
    00CA8EAA  push        10h  
    00CA8EAC  lea         ecx,[p1]  
    00CA8EAF  call        std::vector<int,std::allocator<int> >::__autoclassinit2 (0CA12FDh)  
    00CA8EB4  lea         ecx,[p1]  
    00CA8EB7  call        std::vector<int,std::allocator<int> >::vector<int,std::allocator<int> > (0CA131Bh)  
    00CA8EBC  mov         dword ptr [ebp-4],0  
        p1.push_back(1);
    00CA8EC3  mov         dword ptr [ebp-0F0h],1  
        p1.push_back(1);
    00CA8ECD  lea         eax,[ebp-0F0h]  
    00CA8ED3  push        eax  
    00CA8ED4  lea         ecx,[p1]  
    00CA8ED7  call        std::vector<int,std::allocator<int> >::push_back (0CA17EEh)  
    
    }
    00CA8EDC  mov         dword ptr [ebp-4],0FFFFFFFFh  
    00CA8EE3  lea         ecx,[p1]  
    00CA8EE6  call        std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (0CA14C9h)  
    00CA8EEB  push        edx  
    00CA8EEC  mov         ecx,ebp  
    00CA8EEE  push        eax  
    00CA8EEF  lea         edx,ds:[0CA8F28h]  
    00CA8EF5  call        @_RTC_CheckStackVars@8 (0CA1514h)  
    00CA8EFA  pop         eax  
    00CA8EFB  pop         edx  
    00CA8EFC  mov         ecx,dword ptr [ebp-0Ch]  
    00CA8EFF  mov         dword ptr fs:[0],ecx  
    00CA8F06  pop         ecx  
    00CA8F07  pop         edi  
    00CA8F08  pop         esi  
    00CA8F09  pop         ebx  
    00CA8F0A  mov         ecx,dword ptr [ebp-10h]  
    00CA8F0D  xor         ecx,ebp  
    00CA8F0F  call        @__security_check_cookie@4 (0CA141Fh)  
    00CA8F14  add         esp,0F4h  
    00CA8F1A  cmp         ebp,esp  
    00CA8F1C  call        __RTC_CheckEsp (0CA14CEh)  
    00CA8F21  mov         esp,ebp  
    00CA8F23  pop         ebp  
    00CA8F24  ret  
    
    }
    
    

    很明显编译主动调用了std::vector<int,std::allocator<int> >::~vector<int,std::allocator<int> > (0CA14C9h) 这个析构函数
    ,如果成员变量指向了堆上的数据,请释放,并置NULL;
    这只是冰山一角,好多都是编译器帮你做了什么。而且还是隐式的。
    栈上的数据就如果在覆盖前,其实还是能拿到的、

    Base test4() {
    
        Base p1;
        p1.a = 10;
        printf("0x%x", &p1);
        return p1;
    }
    
    
    
    int main()
    {
        Base p1=  test4();
        return EXIT_SUCCESS;
    }
    

    你可以打断点查看main这个p1,即使调用析构函数.在覆盖前,你还是可以看到的,这个对象还在不子,就看覆盖没有覆盖。
    这是帮助你理解自动释放。我自己的心得,之前也从未想过这个问题。可能你早已知道这些,但是我的心得。

    相关文章

      网友评论

          本文标题:栈上的对象你以为是真的“自动释放”的吗

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