15 临时对象
1 问题
-
下面的程序输出什么?为什么?
class Test { int mi; public: Test(int i) { mi = i; } Test() { Test(0); // 直接调用构造函数:产生一个临时对象,等价于空语句 } void print() { printf("mi = %d\n",mi); } }; int main() { Test t; t.print(); // mi = -1080889604 return 0; }
-
程序分析
-
程序的意图
- 在
Test()
中以 0 作为参数调用Test(int i)
- 将成员变量
mi
的初始值设为 0
- 在
-
运行的结果
- 成员变量
mi
的值为随机值
- 成员变量
-
哪个地方出了问题?
-
-
【问题】构造函数是一个特殊的函数
- 是否可以直接调用
- 是否可以在构造函数中调用构造函数?
- 直接调用构造函数的行为是什么?
-
分析
- 直接调用构造函数将产生一个临时对象
- 临时对象的生命周期只有一条语句的时间
- 临时对象的作用域只在一条语句中
- 临时对象是 C++ 中值得警惕的灰色地带
2 解决方案
-
Demo
#include <stdio.h> class Test { int mi; void init(int i) { mi = i; } public: Test(int i) { init(i); } Test() { init(0); } void print() { printf("mi = %d\n", mi); } }; int main() { Test t; t.print(); // mi = 0 return 0; }
-
编译器的行为
- 现代 C++ 编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生
-
示例:临时对象
-
Demo
#include <stdio.h> class Test { int mi; public: Test(int i) { printf("Test(int i) : %d\n", i); mi = i; } Test(const Test& t) { printf("Test(const Test& t) : %d\n", t.mi); mi = t.mi; } Test() { printf("Test()\n"); mi = 0; } int print() { printf("mi = %d\n", mi); } ~Test() { printf("~Test()\n"); } }; Test func() { return Test(20); // 函数返回一个临时对象 } int main() { Test t = Test(10); // 1.生成临时对象,调用构造函数 2.利用临时对象初始化一个对象,调用拷贝构造函数 => 编译器优化 <=> Test t = 10; => 只调用一次构造函数 Test tt = func(); // 1.生成临时对象,调用构造函数 2.利用函数返回的临时对象初始化一个对象,调用拷贝构造函数 => 编译器优化 <=> Test tt = Test(20); <=> Test tt = 20; =>只调用一次构造函数 t.print(); tt.print(); return 0; }
-
编译运行
Test(int i) : 10 Test(int i) : 20 mi = 10 mi = 20 ~Test() ~Test()
-