我们在程序中不可避免的会遇到临时变量,那么在 C++ 中也会不可避免的会遇到临时对象。我们以代码为例来进行分析

#include<stdio.h>classTest{private:intmi;public:Test(inti){mi=i;}Test(){Test(0);}voidprint(){printf("mi=%d\n",mi);}};intmain(){Testt;t.print();return0;}

我们这段代码是想要在 Test() 中以 0 作为参数调用 Test(int i),然后将成员变量 mi 初始化为 0,最后想要打印它的值。我们来看看编译结果

我们看到打印的是一个随机数,并不是我们所期望的 0。那这到底是怎么回事呢?那么我们想下:构造函数既然是一个特殊的函数。那么它是否可以直接调用呢?是否可以在构造函数中调用构造函数呢?直接调用构造函数的行为是什么?我们就直接说答案了。直接调用构造函数将产生一个临时对象,临时对象的生命周期只有一条语句的时间,临时对象的作用域只在一条语句中,临时对象是 C++ 中值得警惕的灰色地带!上面那个程序也就是说第 15 行的调用的构造函数会产生临时对象,它的生命周期只有那一行的时间,所以在后面我们打印出来的才会是一个随机值。

下面我们在上面程序的基础上进行修改,代码如下

#include<stdio.h>classTest{private:intmi;voidinit(inti){mi=i;}public:Test(){init(0);}voidprint(){printf("mi=%d\n",mi);}};intmain(){Testt;t.print();return0;}

我们再次编译看看结果

这次我们看到它按照我们所想要的初始化为 0 了。现代的 C++ 编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生!!!

我们再来看一个示例代码

#include<stdio.h>classTest{private:intmi;public:Test(inti){mi=i;printf("Test(inti):%d\n",mi);}Test(constTest&obj){mi=obj.mi;printf("Test(constTest&obj):%d\n",mi);}Test(){mi=0;printf("Test()\n");}voidprint(){printf("mi=%d\n",mi);}~Test(){printf("~Test()\n");}};Testfunc(){returnTest(50);}intmain(){Testt=Test(10);Testtt=func();t.print();tt.print();return0;}

我们看到在第 40 行定义了 Test 对象 t,并将它初始化为 10。按照我们想的它在这块先是生成一个临时对象初始化为 10 并将这个临时对象赋值给对象 t。所以这块可能会牵扯到拷贝构造函数。第 41 行也是这样的,先是在 func 函数中生成一个临时对象 Test(50),并将它赋值给对象 tt。所以也会牵扯到拷贝构造函数。那么我们来编译下看看结果

我们看到并没有打印出拷贝构造函数的身影。再回想下我们之前讲的,现代编译器已经大大优化了,尽量会避免临时对象的产生。那么第 40 行将会等价于 Test t(10),第 41 行将会等价于 Test tt = Test(50) ==> Test tt(50);所以这样也就能解释清楚了,它确实没牵扯到拷贝构造函数。我们得随时注意 C++ 中的临时对象,因为它将会导致一些莫名其妙的结果。通过对临时对象的学习,总结如下:1、直接调用构造函数将产生一个临时对象,临时对象是性能的瓶颈,也是 bug 的来源之一;2、现代 C++ 编译器会尽力避开临时对象,实际工程开发中需要人为的避开临时对象。


欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083。