神秘的临界对象
有趣的问题
下面的程序输出什么?为什么?
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
}
Test()
{
//等价于//Test(0);
Test(0);//分析:临时对象,作用域与生命周期
}
void print()
{
printf("mi = %d\n",mi);
}
};
int main()
{
Test t;
t.print();
return 0;
}
/*
mi = -434329152
*/
——运行结果:mi的值为随机值。
思考:
- 构造函数是一个特殊的函数
- 是否可以直接调用
- 是否可以在构造函数中调用构造函数
- 直接调用构造函数的行为是什么?
答案:
- 直接调用构造函数将产生一个临时对象
- 临时对象的生命周期只有一条语句的时间
- 临时对象的作用域只在一条语句中
- 临时对象是C++中值得警惕的灰色地带
#include <stdio.h>
class Test
{
private:
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();
return 0;
}
编译器的行为
——现在C++编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生!
#include <stdio.h>
class Test
{
private:
int mi;
public:
Test(int i)
{
printf("Test(int i):%d\n",i);
mi = i;
}
Test()
{
printf("Test()\n");
mi = 0;
}
Test(const Test& t)
{
printf("Test(const Test& t):%d\n",t.mi);
mi = t.mi;
}
void print()
{
printf("mi = %d\n",mi);
}
~Test()
{
printf("~Test()\n");
}
};
Test fun()
{
return Test(20);
}
int main()
{
printf("-----------main begin-----------\n");
//等价于 Test t(10); 等价于 Test t = 10;
Test t = Test(10);
/*
1.生产一个临时对象;
2、用临时对象初始化t对象
==>应该调用拷贝构造函数
*/
/*
原因:
C++编译优化:尽量少调用构造函数,故等价于Test t = 10,以提升运行效率;
*/
t.print();
//被编译器优化:<==>Test tt = Test(20);<==>Test tt = 20;
Test tt = fun();
tt.print();
printf("-----------main end-----------\n");
return 0;
}
小结
-
直接调用构造函数将产生一个临时对象
-
临时对象是性能的瓶颈,也是bug的来源之一
-
现代C++编译器会尽力避开临时对象
-
实际工程开发中需要人为的避开临时对象
//推荐写法
Test t = 10;
//不推荐
Test t(10);
Test t = Test(10);
推荐写法:Test t = 10;
不推荐: Test t(10);和Test t = Test(10);