神秘的临时对象
问题
class Test
{
private :
int mi;
public :
Test(int v)
{
mi = v;
}
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
- 运行结果
- 成员变量mi的值为随机值
究竟什么地方出了问题?
思考
- 构造函数是一个特殊的函数
- 是否可以直接调用?这个是可以的,之前初始化一个数组的时候就是手工调用构造函数
- 是否可以在构造函数中调用构造函数?
- 直接调用构造函数的行为是什么?
答案
- 直接调用构造函数将产生一个临时对象
- 临时对象的生命周期只有一条语句的时间
- 临时对象的作用域只在一条语句当中
- 临时对象是C++中值得警惕的灰色地带
//上面的代码中
Test()
{
Test(0);//这条语句产生了一个临时对象
}
//上面有问题的代码需要这样改:提供一个init()函数
class Test
{
private :
int mi;
void init(int i)
{
mi = i;
}
public :
Test(int v)
{
init(v);
}
Test()
{
init(0);
}
void print()
{
printf("mi = %d\n", mi);
}
};
int main()
{
Test t;
t.print();
return 0;
}
练习
class Test
{
private :
int mi;
void init(int i)
{
mi = i;
}
public :
Test(int v)
{
cout << "Test(int v)" << endl;
init(v);
}
Test()
{
cout << "Test()" << endl;
init(0);
}
void print()
{
printf("mi = %d\n", mi);
}
~Test()
{
cout << "~Test()" << endl;
init(0);
}
};
int main()
{
Test();//临时对象
Test(10);//临时对象
Test().print();//临时对象的print()
Test(10).print();//临时对象的print()
return 0;
}
打印结果: Test() ~Test() Test(int v) ~Test()
Test() mi = 0; ~Test() Test(int v) mi = 10; ~Test()
- 现在的C++编译器会减少临时对象的产生,C++继承了C语言的高效,所以该杜绝临时对象的地方就会杜绝
#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); // ==> Test t = 10(这也是推荐写法);
//本来应该是拷贝构造函数出现临时对象,
//但是当代的C++编译器会尽力避开临时对象的产生
Test tt = func(); // ==> Test tt = Test(20); ==> Test tt = 20;
t.print();
tt.print();
return 0;
}
小结
- 直接调用构造函数将产生一个临时对象。在C语言中出现bug的原因就是野指针,而在C++中的bug就是临时对象
- 临时对象是性能的瓶颈,也是bug的来源之一
- 现代C++编译器会尽力避开临时对象
- 实际工程开发需要人为的避开临时对象
Alipay
Wechat