zoukankan      html  css  js  c++  java
  • 临时对象问题

    http://topic.csdn.net/t/20060412/19/4682278.html

    比如我重载了+运算符,然后返回integer对象  
      return   integer   (left.i   +   right.i)   ;  
      书上说:"这样情况时,编译器明白对创建的对象没有其他需求,只是返回它,所以编译器直接地把这个对象创建在返回值外面的内存单元。因为不是真正创建一个局部对象,所以仅需要单个的普通构造函数调用(不需要拷贝构造函数),并且不会调用析构函数。因此,这种方法不需要什么花费,效率是非常高的。  
       
      我的问题是:1.里面说指的外面的内存单元指的是什么?  
      2.既然调用了普通的构造函数,为什么退出作用域时不会调用析构函数?

    >>>>>>>  answer

    首先要知道临时类如何使用  
       
      比如:  
      class   MyInt  
      {  
      public:  
              MyInt()         {   printf("Constructing...\n");   }  
              ~MyInt()       {   printf("Destructing...\n");     }  
      };  
       
      然后使用以下测试代码:  
      MyInt   GetMyInt()  
      {  
              return   MyInt();  
      }  
       
      int   main(int   argn,   char   *argv[])  
      {  
              GetMyInt();  
              printf("Done   of   GetMyInt().\n");  
              return   -1;  
      }  
      运行后你应看到以下结果:  
      Constructing...                                               //   在函数GetMyInt()中  
      Destructing...                                                 //   在函数main()中  
      printf("Done   of   GetMyInt().\n");             //   在函数main()中,GetMyInt()后  
       
      也就是class   MyInt的实例的确存在过,并且曾经构造并析构。  
      实际上,在GetMyInt()返回时,return会在堆栈中找到返回内存,并以此调用构造函数;在返回以后,main使用完毕了此类(本例中并没有任何使用)后,调用了类的析构函数,然后继续。  
       
      所谓的外面的内存,实际上就是指上一级函数栈的空间,也就是承载返回值的空间,一般来说,返回值都是使用寄存器(如x86上一般都使用ax/eax/rax),但是如果返回的是结构、类,则是内存。  
       
      +------------------+-----------------------+--------------+  
      |   GetMyInt()   stack   |   GetMyInt()   parameters   |   main()   stack   |  
      +------------------+-----------------------+---------------  
      在return时,前面的stack   &   parameters都会被弹出(add   esp,   xxx),然后再保留一个空间作为返回值(sub   esp,   sizeof(class   MyInt)),然后以esp为指针构造类。返回以后,main可以直接使用并在使用完毕以后析构。  
       
      为了进一步分析,采用以下例子:  
       
      class   MyInt  
      {  
      public:  
              MyInt()         {   printf("Constructing...\n");   }  
              ~MyInt()       {   printf("Destructing...\n");     }  
              operator   +(class   MyInt   &m2)   {   printf("Add!\n");   };  
      };  
       
      MyInt   GetMyInt()  
      {  
              return   MyInt();  
      }  
       
      int   main(int   argn,   char   *argv[])  
      {  
              GetMyInt()   +   GetMyInt();  
              printf("Done   of   GetMyInt().\n");  
              return   -1;  
      }  
       
      运行以后应该看到:  
      Constructing...                                 //   第一次调用GetMyInt()函数内  
      Constructing...                                 //   第二次调用GetMyInt()函数内  
      Add!                                                       //   main()函数内  
      Destructing...                                   //   main()函数内,表达式完毕  
      Destructing...                                   //   main()函数内,表达式完毕  
      Done   of   GetMyInt().  
      看到此例的结果,应该明白构造、析构的情况。  
       
      关于栈的情况,可以将类的构造函数修改为:  
              MyInt()         {   int   _esp;   __asm   {   mov   _esp,   esp   };   printf("Constructing...   %p,   esp   =   %p\n",   this,   _esp);   }  
       
      运行后,结果类似如下(具体值会有不同,和机器、编译器、操作系统相关)  
      Constructing...   0012FF6C,   esp   =   0012FE58  
      Constructing...   0012FF70,   esp   =   0012FE54  
      Add!  
      Destructing...  
      Destructing...  
      Done   of   GetMyInt().  
      可以注意到,两次construct的this地址偏移差是sizeof(MyInt),和esp相当接近(不会相等,因为构造函数本身也需要使用栈)  

  • 相关阅读:
    shell基础--变量的数值计算
    shell基础--字符串和变量的操作
    shell基础--shell特殊变量
    Asp.net MVC 控制器扩展方法实现jsonp
    ASP.NET web api 跨域请求
    asp.net Web API简单的特性路由配置
    ASP.Net Web API 输出缓存 转载 -- Output caching in ASP.NET Web API
    基础拾遗 C# Json 与对象相互转换
    内存溢出和内存泄漏
    软件测试面试题(一)
  • 原文地址:https://www.cnblogs.com/carl2380/p/1924606.html
Copyright © 2011-2022 走看看