第23课 神秘的临时对象

有趣的问题:

我们在无参构造函数中调用带一个参数的构造函数。

程序如下:

 1 #include <stdio.h>
 2 
 3 class Test {
 4     int mi;
 5 public:
 6     Test(int i) {
 7         mi = i;
 8     }
 9     Test() {
10         Test(0);
11     }
12     void print() {
13         printf("mi = %d\n", mi);
14     }
15 };
16 
17 
18 int main()
19 {
20     Test t;
21     
22     t.print();
23 
24     return 0;
25 }

运行结果如下:

mi并没有打印出0,而是一个随机值。

发生了什么呢?

思考:

构造函数可以直接手工调用。

上面的程序第10行直接调用了构造函数产生了临时对象。它的生命期只有第10行这一条语句,过了这条语句就会被析构。

而且这个临时对象没有名字,作用域也仅仅在第10行这条语句中。第10行这条语句等价于没有,也就是空语句,因为这个临时对象我们无法使用。

我们在无参构造函数中调用有参构造函数的本意是代码复用,但是没有达到目的,在工程中,代码复用时,我们要在类中提供一个普通的init函数,这时就可以将公共代码写到这个函数中。

 临时对象示例:

由临时对象直接调用成员函数:

可以看到临时对象构造完之后立即调用了打印函数。

工程中要避免临时对象的产生与使用。

编译器的行为:

现代编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生。

示例如下:

 1 #include <stdio.h>
 2 
 3 class Test
 4 {
 5     int mi;
 6 public:
 7     Test(int i)
 8     {
 9         printf("Test(int i) : %d\n", i);
10         mi = i;
11     }
12     Test(const Test& t)
13     {
14         printf("Test(const Test& t) : %d\n", t.mi);
15         mi = t.mi;
16     }
17     Test()
18     {
19         printf("Test()\n");
20         mi = 0;
21     }
22     int print()
23     {
24         printf("mi = %d\n", mi);
25     }
26     ~Test()
27     {
28         printf("~Test()\n");
29     }
30 };
31 
32 Test func()
33 {
34     return Test(20);
35 }
36 
37 int main()
38 {
39     Test t = Test(10); // ==> Test t = 10;
40     Test tt = func();  // ==> Test tt = Test(20); ==> Test tt = 20;
41     
42     t.print();
43     tt.print();
44     
45     return 0;
46 }

39行的Test t = 10和Test t = Test(10)的编译运行结果是一样的。

Test t = Test(10)在我们的直觉判断会有以下两步,1、创建临时对象;2、用临时对象初始化t(调用拷贝构造函数)。

但是程序执行结果并不是按照我们的直觉分析那样的,这就是因为编译器做了优化。编译器会尽力减少临时对象的产生。

编译器将Test t = Test(10)等价成了Test t = 10的形式。

临时对象的产生会带来性能上面问题。

工程中的构造函数会非常复杂,调用一次构造函数耗时很长。

上述程序的运行结果如下:

32-35行返回临时对象,然后在40行用这个对象初始化tt,但是从打印结果可以看出,构造函数并不是按照我们想象的情形来调用的,我们想象的情形是先调用构造函数产生临时对象,然后调用拷贝构造函数初始化tt。运行结果没有调用拷贝构造函数。

这也是因为编译器的优化,在不影响执行结果的前提下会极力的减少临时对象的产生。

我们写程序也应该尽力的避开临时对象,例如程序写成Test t = 10,而不是Test t  = Test(10)。这样就可以保证在任何一款编译器下都不会产生临时对象。

小结:

猜你喜欢

转载自www.cnblogs.com/wanmeishenghuo/p/9569753.html