我们在程序中不可避免的会遇到临时变量,那么在 C++ 中也会不可避免的会遇到临时对象。我们以代码为例来进行分析
#include <stdio.h> class Test { private: int mi; public: Test(int i) { mi = i; } Test() { Test(0); } void print() { printf("mi = %d\n", mi); } }; int main() { Test t; t.print(); return 0; }
我们这段代码是想要在 Test() 中以 0 作为参数调用 Test(int i),然后将成员变量 mi 初始化为 0,最后想要打印它的值。我们来看看编译结果
我们看到打印的是一个随机数,并不是我们所期望的 0。那这到底是怎么回事呢?那么我们想下:构造函数既然是一个特殊的函数。那么它是否可以直接调用呢?是否可以在构造函数中调用构造函数呢?直接调用构造函数的行为是什么?我们就直接说答案了。直接调用构造函数将产生一个临时对象,临时对象的生命周期只有一条语句的时间,临时对象的作用域只在一条语句中,临时对象是 C++ 中值得警惕的灰色地带!上面那个程序也就是说第 15 行的调用的构造函数会产生临时对象,它的生命周期只有那一行的时间,所以在后面我们打印出来的才会是一个随机值。
下面我们在上面程序的基础上进行修改,代码如下
#include <stdio.h> class Test { private: int mi; void init(int i) { mi = i; } public: Test() { init(0); } void print() { printf("mi = %d\n", mi); } }; int main() { Test t; t.print(); return 0; }
我们再次编译看看结果
这次我们看到它按照我们所想要的初始化为 0 了。现代的 C++ 编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生!!!
我们再来看一个示例代码
#include <stdio.h> class Test { private: int mi; public: Test(int i) { mi = i; printf("Test(int i): %d\n", mi); } Test(const Test& obj) { mi = obj.mi; printf("Test(const Test& obj): %d\n", mi); } Test() { mi = 0; printf("Test()\n"); } void print() { printf("mi = %d\n", mi); } ~Test() { printf("~Test()\n"); } }; Test func() { return Test(50); } int main() { Test t = Test(10); Test tt = func(); t.print(); tt.print(); return 0; }
我们看到在第 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。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。