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相当接近(不会相等,因为构造函数本身也需要使用栈)