比如我重载了+运算符,然后返回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相当接近(不会相等,因为构造函数本身也需要使用栈)