关于无名对象与临时对象
#include <iostream.h>
class X
{
int c;
public:
X(int);
X(X&);
~X();
};
X::X(int t)
{
cout < < "construct normal: " < <t < <endl;
c = t;
}
X::X(X& t)
{
cout < < "construct copy: " < <t.c < <endl;
c = t.c;
}
X::~X()
{
cout < < "destory: " < <this-> c < <endl;;
}
X f(X t)
{
X temp(5);
return temp;
}
void main()
{
X a(1);
X b = f(X(2));
a = f(a);
}
输出结果为:
construct normal:1
construct normal:2
construct normal:5
construct copy:5
destory:5
destory:2
construct copy:1
construct normal:5
construct copy:5
destory:5
destory:1
destory:5
destory:5
destory:5
本来我的分析是:
X a(1); 调用构造函数X::X(int t)输出construct normal:1
X b = f(X(2));
这句按理说是:
1,先调用X::X(int t)构造一个无名对象,然后调用X::X(X& t)用实参初始化形参.不过书上说:对于X k = X(1);这种情况,C++将其看作X k = 1,省略创建无名对象一步.按照这种说法的话,这里会调用X::X(int t)直接构造形参.
2,调用X::X(int t)构造temp局部对象,返回局部对象时,调用X::X(X& t)用temp初始化临时对象,析构temp局部对象,析构形参对象;
3,返回主函数后调用X::X(X& t)用临时对象初始化b,析构临时对象.
a = f(a);
这句按理说是:
1,调用X::X(X& t)用a初始化函数形参;
2,调用X::X(int t)构造temp局部对象,返回局部对象时,调用X::X(X& t)用temp初始化临时对象,析构temp局部对象,析构形参对象;
3,返回主函数后将临时对象赋值给a,然后析构临时对象.
最后以构造顺序相反的顺序析构主函数中的对象,本来是无名对象,对象b,对象a;因为无名对象没有真正构造,所以只有对象b,对象a.
按照上面的分析,输出语句应该是:
construct normal:1
construct normal:2
construct normal:5
construct copy:5
destory:5
destory:2
construct copy:5
destory:5
construct copy:1
construct normal:5
construct copy:5
destory:5
destory:1
destory:5
destory:5
destory:5
比显示结果多了两条:
construct copy:5
destory:5
即少了用临时对象初始化对象b和临时对象的析构,为什么?
我看的是清华大学出版社钱能的 <C++程序设计教程> ,根据书上讲的自己对这个程序的分析.
[解决办法]
看 <exceptional C++> item 42
[解决办法]
因为2,3点是相关的
"第二次,用临时对象初始化X b "
此时是赋值行为,不会调用拷贝构造函数,
我说了,调用拷贝函数会生成对象, 赋值不等于调用拷贝函数
通俗点说:
记用局部对象temp初始化临时对象为 T
X b = f(); 是给T起个名字 "b "
X b;
b = f(); 是把T的值赋给b
两者都会调用拷贝函数初始化临时对象,临时对象都会析构
所以只执行了一次拷贝函数和一次析构函数
记住,这对临时对象的创建和析构
"那么总共调用了两次拷贝构造函数(第一次:用局部对象temp初始化临时对象,第二次,用临时对象初始化X b),也调用了两次析构函数(第一次:局部对象temp被析构;第二次:临时对象被析构)。 "
修改一下你的说法:
"那么总共调用了一次拷贝构造函数(第一次:用局部对象temp初始化临时对象(创建对象),第二次,把临时对象赋值X b(赋值)),调用了两次析构函数(第一次:局部对象temp被析构(临时对象无关,只是你 X temp(5); 才有这次析构);第二次:临时对象被析构(分两种情况,当b与临时对象为同一体,临时对象的生存周期就为b的周期;当不是同一体,临时对象的周期到下一句结束))。 "
完全正确,
要注意的是 X b = f(); 时b和临时对象是同一体了,该临时对象的析构就相当于b被析构
X b;
b = f(); b和临时对象的析构完全不相干
由于存在这两种情况,所以把你弄混了,你把mian函数改为
void main()
{
X a(1);
X b(1);
b= f(X(2));
a = f(a);
}
吧,应该会得出你想要的结果
经鉴定,你是把拷贝函数和赋值弄混了, 拷贝函数可以说是构造函数的一种
PS:最后一次回复,我已经写得很明白了,再不明白我也没办法