临时对象生成的三种条件 :
①形参为对象,实参为数值常量,传参就会生成临时对象
②隐式类型转换
③函数返回一个对象
先定义一个 Test 对象
class Test
{
public:
Test()
{
ma = mb = 0;
std::cout<<"Test()"<< std::endl;
}
Test(int a)
{
ma = a;
mb = 0;
std::cout<<"Test(int)"<< std::endl;
}
Test(int a, int b)
{
ma = a;
mb = b;
std::cout<<"Test(int,int)"<< std::endl;
}
//以上是三个不同的构造函数
Test(const Test& rhs) //因为没有指针所以不需要深拷贝
{
ma = rsh.ma;
mb = rsh.mb;
std::cout<<"Test(const Test&)"<< std::endl;
}
~Test()
{
std::cout << "~Test()" << std::endl;
}
Test& operator=(const Test& rhs)
{
if(this != &rhs)
{
ma = rhs.ma;
mb = rhs.mb;
}
std::cout<<"operator="<< std::endl;
return *this;
}
private:
int ma;
int mb;
};
Test func1(const Test& ts)
{
Test tmp(ts);
std::cout << "void func1(const Test&)" << std::endl;
return tmp;
}
Test func2(Test ts)
{
std::cout << "void func2(const Test&)" << std::endl;
return ts;
}
int main()
{
Test a = 10;
a = 20;
const Test& b = 20;
Test test1(10,20);
Test rt = func1(test1);
Test c = func2(30);
return 0;
}
用几个例子说明一下临时对象的生存周期
Test a = 10;
这个语句时可以运行成功的,那么是如何做到将一个整形值赋值给一个对象的呢?首先,调用一个整形参数的构造函数 ,生成一个临时对象,而这个临时对象的生成是为了生成一个新对象,所以就以生成临时对象的方式生成 a 这个对象,这样就可以少生成一次对象,从而达到优化的效果。因此这个对象的生存周期从这句开始一直到该函数运行结束。
a = 20;
这个语句的运行和上面那句有一点不同,首先还是调用一个整形参数的构造函数,生成一个临时对象,而这个临时对像的生成不是为了生成新对象,所以这个临时对象的生存周期到这个语句执行结束。
const Test& b = 20;
执行这条语句时, 首先还是调用一个整形参数的构造函数,生成一个临时对象,临时对象是为了生成新对象,所以被优化,直接生成 b 这个临时对象。而 b 这个对象加了引用(引用能提升临时对象的生存周期,提升为和引用变量相同的生存周期),所以对象 b 的生存周期一直到该程序结束
Test* ptest1 = &Test(10,20) ;
分析这条语句,赋值符号右边调用两个int型参数的构造函数生成一个临时对象,对其取地址,并赋值给Test型的指针。看上去貌似没有问题,但是由于生成的是临时对象,并且没有引用提升生存周期,所以该指针指向一个临时对象,在执行完这条语句后,用该指针访问这段内存,值不会改变,但是以后系统可能会把该段内存分配给其他变量或者函数,那时候用ptest1访问就会造成无法估计的后果
Test rt = func1(Test ts);
主函数调用func1函数,那么实参传形参的时候,生成临时对象的生存周期一直到该函数调用结束,而返回的对象由临时量带回,返回值返回的也是一个临时对象,在调用方的栈帧上,临时对象的生成是为了生成一个新对象,所以被优化了。因此这个对象的生存周期到主函数结束。
Test c = func2(30);
这条语句执行的时候,首先调用func2函数,然后实参传形参,先调用一个整形参数的构造函数,生成一个临时对象,接着调用拷贝构造函数,将临时对象中的值赋给 ts,执行func2中的return语句时,由于返回的是一个对象,返回值有临时量带回调用方函数,main中,c 接收函数的返回值,c 并不是个已存在的对象,因此调用拷贝构造函数生成c。