⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 [c++对象模型][5]堆栈与函数调用 - itech's blog - 博客园.htm

📁 最为全面的c++内存模型探秘。不管是初学者还是老手
💻 HTM
📖 第 1 页 / 共 5 页
字号:
style="COLOR: #800000">123456</SPAN><SPAN style="COLOR: #800000">"</SPAN><SPAN 
style="COLOR: #000000">);&nbsp;&nbsp; </SPAN><SPAN 
style="COLOR: #008000">//</SPAN><SPAN 
style="COLOR: #008000">123456\0放在常量区,编译器可能会将它与p3所向"123456\0"优化成一个地方。</SPAN><SPAN 
style="COLOR: #008000"> <BR></SPAN><SPAN 
style="COLOR: #000000">}</SPAN></SPAN></DIV>
<P>&nbsp;</P>
<P>二 三种内存对象的比较 
<BR>  栈对象的优势是在适当的时候自动生成,又在适当的时候自动销毁,不需要程序员操心;而且栈对象的创建速度一般较堆对象快,因为分配堆对象时,会调用operator 
new操作,operator 
new会采用某种内存空间搜索算法,而该搜索过程可能是很费时间的,产生栈对象则没有这么麻烦,它仅仅需要移动栈顶指针就可以了。但是要注意的是,通常栈空间容量比较小,一般是1MB~2MB,所以体积比较大的对象不适合在栈中分配。特别要注意递归函数中最好不要使用栈对象,因为随着递归调用深度的增加,所需的栈空间也会线性增加,当所需栈空间不够时,便会导致栈溢出,这样就会产生运行时错误。 
<BR>  堆对象创建和销毁都要由程序员负责,所以,如果处理不好,就会发生内存问题。如果分配了堆对象,却忘记了释放,就会产生内存泄漏;而如 
果已释放了对象,却没有将相应的指针置为NULL,该指针就是所谓的“悬挂指针”,再度使用此指针时,就会出现非法访问,严重时就导致程序崩溃。但是高效的使用堆对象也可以大大的提高代码质量。比如,我们需要创建一个大对象,且需要被多个函数所访问,那么这个时候创建一个堆对象无疑是良好的选择,因为我们通过在各个函数之间传递这个堆对象的指针,便可以实现对该对象的共享,相比整个对象的传递,大大的降低了对象的拷贝时间。另外,相比于栈空间,堆的容量要大得多。实际上,当物理内存不够时,如果这时还需要生成新的堆对象,通常不会产生运行时错误,而是系统会使用虚拟内存来扩展实际的物理内存。</P>
<P>  静态存储区。所有的静态对象、全局对象都于静态存储区分配。关于全局对象,是在main()函数执行前就分配好了的。其实,在main()函数中的显示代 
码执行之前,会调用一个由编译器生成的_main()函数,而_main()函数会进行所有全局对象的的构造及初始化工作。而在main()函数结束之 
前,会调用由编译器生成的exit函数,来释放所有的全局对象。比如下面的代码: 
<TABLE cellPadding=0 border=1>
  <TBODY>
  <TR>
    <TD>
      <P>void main(void) <BR>{ <BR>… …// 显式代码 <BR>}</P></TD></TR></TBODY></TABLE></P>
<P>实际上,被转化成这样: 
<TABLE cellPadding=0 border=1>
  <TBODY>
  <TR>
    <TD>
      <P>void main(void) <BR>{ <BR>_main(); //隐式代码,由编译器产生,用以构造所有全局对象 <BR>… … // 
      显式代码 <BR>… … <BR>exit() ; // 隐式代码,由编译器产生,用以释放所有全局对象 
<BR>}</P></TD></TR></TBODY></TABLE></P>
<P>  除了全局静态对象,还有局部静态对象通和class的静态成员,局部静态对象是在函数中定义的,就像栈对象一样,只不过,其前面多了个static关键字。局部静态对象的生命期是从其所在函数第一次被调用,更确切地说,是当第一次执行到该静态对象的声明代码时,产生该静态局部对象,直到整个程序结束时,才销毁该对象。class的静态成员的生命周期是该class的第一次调用到程序的结束。</P>
<P>三 函数调用与堆栈</P>
<P>1)编译器一般使用栈来存放函数的参数,局部变量等来实现函数调用。有时候函数有嵌套调用,这个时候栈中会有多个函数的信息,每个函数占用一个连续的区域。一个函数占用的区域被称作帧(frame)。同时栈是线程独立的,每个线程都有自己的栈。例如下面简单的函数调用:</P>
<P><IMG height=365 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022318570052.png" 
width=488></P>
<P>另外函数堆栈的清理方式决定了当函数调用结束时由调用函数或被调用函数来清理函数帧,在VC中对函数栈的清理方式由两种:</P>
<TABLE style="HEIGHT: 94px" width="80%" border=2>
  <TBODY>
  <TR>
    <TD width="16%"><BR></TD>
    <TD width="24%">参数传递顺序</TD>
    <TD width="60%">谁负责清理参数占用的堆栈</TD></TR>
  <TR>
    <TD>__stdcall</TD>
    <TD>从右到左</TD>
    <TD>被调函数</TD></TR>
  <TR>
    <TD>__cdecl </TD>
    <TD>从右到左</TD>
    <TD>调用者</TD></TR></TBODY></TABLE>
<P>2) 有了上面的知识为铺垫,我们下面细看一个函数的调用时堆栈的变化:</P>
<P>代码如下:</P>
<P>&nbsp;</P>
<DIV class=cnblogs_code><IMG id=Code_Closed_Image_191809 style="DISPLAY: none" 
onclick="this.style.display='none'; document.getElementById('Code_Closed_Text_191809').style.display='none'; document.getElementById('Code_Open_Image_191809').style.display='inline'; document.getElementById('Code_Open_Text_191809').style.display='inline';" 
height=16 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/ContractedBlock.gif" 
width=11 align=top><IMG id=Code_Open_Image_191809 
onclick="this.style.display='none'; document.getElementById('Code_Open_Text_191809').style.display='none'; getElementById('Code_Closed_Image_191809').style.display='inline'; getElementById('Code_Closed_Text_191809').style.display='inline';" 
height=16 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/ExpandedBlockStart.gif" 
width=11 align=top><SPAN class=cnblogs_code_Collapse 
id=Code_Closed_Text_191809>Code</SPAN><SPAN id=Code_Open_Text_191809><BR><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;Add(</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;x,&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;y)<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">return</SPAN><SPAN 
style="COLOR: #000000">&nbsp;x&nbsp;</SPAN><SPAN 
style="COLOR: #000000">+</SPAN><SPAN 
style="COLOR: #000000">&nbsp;y;<BR>}<BR><BR></SPAN><SPAN 
style="COLOR: #0000ff">void</SPAN><SPAN 
style="COLOR: #000000">&nbsp;main()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pi&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN 
style="COLOR: #800080">10</SPAN><SPAN 
style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pj&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN 
style="COLOR: #800080">20</SPAN><SPAN 
style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;result&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #800080">0</SPAN><SPAN 
style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN 
style="COLOR: #000000">&nbsp;Add(</SPAN><SPAN 
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pi,</SPAN><SPAN 
style="COLOR: #000000">*</SPAN><SPAN 
style="COLOR: #000000">pj);<BR>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pi;<BR>&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pj;<BR>}</SPAN></SPAN></DIV>
<P>&nbsp;</P>
<P>对上面的代码,我们分为四步,当然我们只画出了我们的代码对堆栈的影响,其他的我们假设它们不存在,哈哈!</P>
<P>第一,<SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #000000">*</SPAN><SPAN style="COLOR: #000000">pi&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">(</SPAN><SPAN 
style="COLOR: #800080">10</SPAN><SPAN style="COLOR: #000000">);&nbsp;&nbsp; 
</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN 
style="COLOR: #000000">pj&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN 
style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN 
style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #800080">20</SPAN><SPAN 
style="COLOR: #000000">);&nbsp;&nbsp; </SPAN><SPAN 
style="COLOR: #0000ff">int</SPAN><SPAN 
style="COLOR: #000000">&nbsp;result&nbsp;</SPAN><SPAN 
style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN 
style="COLOR: #800080">0</SPAN><SPAN style="COLOR: #000000">; 
堆栈变化如下:</SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN style="COLOR: #000000"><IMG height=514 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022319424760.png" 
width=428></SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">第二,</SPAN></SPAN><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">Add(</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN 
style="COLOR: #000000">pi,</SPAN><SPAN style="COLOR: #000000">*</SPAN><SPAN 
style="COLOR: #000000">pj);堆栈如下:</SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN style="COLOR: #000000"><IMG height=514 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022319432312.png" 
width=431></SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">第三,将Add的结果给result,堆栈如下:</SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN style="COLOR: #000000"><IMG height=516 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022319435828.png" 
width=431></SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">第四,</SPAN></SPAN><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">delete&nbsp;pi;&nbsp;&nbsp;&nbsp; delete&nbsp;pj; 
堆栈如下:</SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN style="COLOR: #000000"><IMG height=513 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022319443455.png" 
width=429></SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN 
style="COLOR: #000000">第五,当main()退出后,堆栈如下,等同于main执行前,哈哈!</SPAN></SPAN></P>
<P><SPAN id=Code_Open_Text_191809><SPAN style="COLOR: #000000"><IMG height=517 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/2009022319490437.png" 
width=435><BR></SPAN></SPAN></P>
<P>四 完!</P>
<DIV id=MySignature>
<P>感谢,Thanks!<BR><BR>作者:<A href="http://itech.cnblogs.com/">iTech</A><BR>出处:<A 
href="http://itech.cnblogs.com/">http://itech.cnblogs.com/</A> 
<BR>转载:本文版权归作者iTech所有,转载请注明出处,不得用于商业用途!</P></DIV>
<DIV id=EntryTag>Tag标签: <A 
href="http://www.cnblogs.com/itech/tag/[Cpp对象模型]/">[Cpp对象模型]</A></DIV></DIV>
<DIV class=postDesc>posted @ 2009-02-23 19:49 <A 
href="http://www.cnblogs.com/itech/">iTech</A> 阅读(89) <A 
href="http://www.cnblogs.com/itech/archive/2009/02/23/1395515.html#Post">评论(0)</A> 
&nbsp;<A 
href="http://www.cnblogs.com/itech/admin/EditPosts.aspx?postid=1395515">编辑</A> 
<A href="http://www.cnblogs.com/itech/AddToFavorite.aspx?id=1395515">收藏</A> <A 
onclick="PutInWz();return false;" 
href="http://www.cnblogs.com/itech/archive/2009/02/23/1395515.html#">网摘</A> 
所属分类: <A href="http://www.cnblogs.com/itech/category/170009.html">C++</A> 
</DIV></DIV><IMG height=1 
src="[C++对象模型][5]堆栈与函数调用 - iTech's Blog - 博客园.files/1395515.jpg" width=1> <!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
rdf:about="http://www.cnblogs.com/itech/archive/2009/02/23/1395515.html"
dc:identifier="http://www.cnblogs.com/itech/archive/2009/02/23/1395515.html"
dc:title=""
trackback:ping="http://www.cnblogs.com/itech/services/trackbacks/1395515.aspx" />
</rdf:RDF>
--></DIV><!--end: topics 文章、评论容器-->
<DIV id=AjaxHolder_UpdatePanel1>
<STYLE>TD {
	FONT-SIZE: 12px
}
.commentTextBox {
	FONT-SIZE: 13px; FONT-FAMILY: Verdana
}
A.blue:visited {
	COLOR: blue
}
A.blue:active {
	COLOR: blue
}
A.blue:link {
	COLOR: blue
}
A.blue:hover {
	COLOR: blue
}
</STYLE>
<!--Beging Temp Save-->
<STYLE>.userData {
	BEHAVIOR: url(#default#userdata)
}
</STYLE>

<DIV class=userData id=CommentsPersistDiv></DIV>
<SCRIPT type=text/javascript>
    function pageLoad() {
        Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(handleInitializeRequest);
        //Sys.WebForms.PageRequestManager.getInstance().add_endRequest(handleEndRequest);
    }

    function handleInitializeRequest(sender, args) {
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        var eid = args.get_postBackElement().id;
        /*if (eid.indexOf("DeleteLink")>0) 
        {
        args.get_postBackElement().innerHTML = "<font color='red'>正在删除...</font>";         
        }    
        else */
        if (eid.indexOf("btnSubmit") > 0) {
            document.getElementById("AjaxHolder_PostComment_ltSubmitMsg").innerHTML = "正在提交...";
            document.getElementById("AjaxHolder_PostComment_btnSubmit").disabled = true;
        }
        else if (eid.indexOf("refreshList") > 0) {
            document.getElementById("AjaxHolder_PostComment_refreshList").innerHTML = "<font color='red'>正在刷新...</font>";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -