临时对象分为显式生成和隐式生成
一般没有引用时,临时对象在表达式结束后生命周期结束。
- 显式生成临时对象
显式生成即在生成临时对象时注明临时对象的类型
即 Node n1;
n1=Node(10);
- 隐式生成临时对象
隐式生成即在生成临时对象时并不注明对象的类型,需要编译器的推算。
即 Node n1;
n1=10;
显式生成临时对象与隐式生成临时对象的区别:
显式生成的临时对象时变量,隐式生成的临时对象是常量
例:
#include<iostream>
class Node{
public:
Node(int ma=0)
{
this->ma=ma;
std::cout<<"Node(int ma=0)"<<std::endl;
}
~Node()
{
std::cout<<"~Node()"<<std::endl;
}
Node(const Node& rhs)
{
std::cout<<"Node(const Node& rhs)"<<std::endl;
}
Node& operator=(const Node& rhs)
{
std::cout<<"Node& operator=(Node& rhs)"<<std::endl;
return *this;
}
void Show()
{
std::cout<<"void show() "<<std::endl;
}
private:
int ma;
};
使用Node类来进行测试
显式生成临时对象:
int main()
{
Node n ;
std::cout<<"--------------------"<<std::endl;
n=Node(10);
std::cout<<"--------------------"<<std::endl;
return 0;
}
运行结果:
我们可以看出,可以使用普通对象指针指向临时对象
并且在n=Node(10);这一条语句中调用了构造函数、运算符重载函数和析构函数,
说明临时对象的生存周期在表达式结束就结束。
隐式生成临时对象:
将运算符重载函数的形参改为Node &rhs 而非const Node &rhs
int main()
{
std::cout<<"--------------------"<<std::endl;
Node &n = 10;
std::cout<<"--------------------"<<std::endl;
return 0;
}
程序提示错误,
将运算符重载函数的形参改回const Node &rhs
运行结果:
我们可以看出只有常引用能够引用隐式生成的临时对象.
临时对象的优化:
1.
例:
int main()
{
std::cout<<"+++++++++++"<<std::endl;
Node n1=Node(10);
std::cout<<"++++++++++++"<<std::endl;
std::cout<<"--------------------"<<std::endl;
Node n2=20;
std::cout<<"--------------------"<<std::endl;
return 0;
}
通过上面的知识我们知道Node n1=Node(10) 和 Node n2=20;
都应该生成一个临时对象,但从程序的运行接过来看,并没有生成临时对象。
因为临时对象的目的如果是为了生成新对象,以生成临时对象的的方式生成新对象。
即Node n1(10);和 Node n2(20);直接生成了新对象而没有生成临时对象再调用拷贝构造函数生成新对象
2.
例:
int main()
{
std::cout<<"+++++++++++"<<std::endl;
Node &n1=Node(10);
std::cout<<"++++++++++++"<<std::endl;
std::cout<<"--------------------"<<std::endl;
const Node &n2=20;
std::cout<<"--------------------"<<std::endl;
return 0;
}
从上面的知识我们知道,临时变量的生存周期在表达式结束就结束
但从程序的运行结果我们可以看出,在引用变量引用临时对象后,临时对象的生存周期发生了改变。
因为引用能提升临时对象的生存周期,把临时对象的生存周期提升到和引用变量相同的生存周期。
执行 Node &n1=Node(10);后临时对象的生存周期被提升到和n1的生存周期相同,
n1的生存周期到main函数退栈时结束,此时临时变量的生存周期也就结束,调用析构函数。
const Node &n2=20;与n1相同。
- 返回值为类类型,通过临时对象带出,而并非将局部对象直接返回。
例:
#include<iostream>
class Node{
public:
Node(int ma=0)
{
this->ma=ma;
std::cout<<this<<" Node(int ma=0)"<<std::endl;
}
~Node()
{
std::cout<<this<<" ~Node()"<<std::endl;
}
Node(const Node& rhs)
{
std::cout<<this<<" Node(const Node& rhs) "<<&rhs<<std::endl;
}
Node& operator=(const Node& rhs)
{
std::cout<<"Node& operator=(const Node& rhs)"<<std::endl;
return *this;
}
void Show()
{
std::cout<<"void show() "<<std::endl;
}
private:
int ma;
};
Node get(Node &rhs)
{
std::cout<<"++++++++"<<std::endl;
Node tmp;
std::cout<<"++++++++"<<std::endl;
return tmp;
}
int main()
{
Node n1;
Node n2;
std::cout<<"--------------"<<std::endl;
n1=get(n2);
std::cout<<"--------------"<<std::endl;
return 0;
}
运行结果:
从运行结果和代码对比来看,006FFBF4 即为get()函数中对象tmp,
但tmp在调用析构函数前调用了拷贝构造函数用tmp生成了临时对象006FFC38,将临时变量返回,而并非将局部对象返回(局部对象在函数退栈时就销毁)
在n1=get(n2)表达式结束后,临时变量006FFC38才销毁。
注意:
#include<iostream>
class CGoods
{
public:
CGoods(char* name, float price, int amount)
{
std::cout << this << " :CGoods::CGoods(char*,float, int)" << std::endl;
mname = new char[strlen(name) + 1]();
strcpy(mname, name);
mprice = price;
mamount = amount;
}
CGoods(int amount)
{
std::cout << this << " :CGoods::CGoods(int)" << std::endl;
mname = new char[1]();
mamount = amount;
}
CGoods()
{
std::cout << this << " :CGoods::CGoods()" << std::endl;
mname = new char[1]();
}
~CGoods()
{
std::cout << this << " :CGoods::~CGoods()" << std::endl;
delete[] mname;
mname = NULL;
}
CGoods(const CGoods& rhs)
{
std::cout << this << " :CGoods::CGoods(const CGoods&)" << std::endl;
mname = new char[strlen(rhs.mname) + 1]();
strcpy(mname, rhs.mname);
mprice = rhs.mprice;
mamount = rhs.mamount;
}
CGoods& operator=(const CGoods& rhs)
{
std::cout << this << " :CGoods::operator=(const CGoods&)" << std::endl;
if (this != &rhs)
{
delete[] mname;
mname = new char[strlen(rhs.mname) + 1]();
strcpy(mname, rhs.mname);
mprice = rhs.mprice;
mamount = rhs.mamount;
}
return *this;
}
private:
char* mname;
float mprice;
int mamount;
};
int main()
{
CGoods good;
good = (CGoods)("good8",10.1, 20);
return 0;
}
我们在遇到good=(Goods)(good8",10.1,20);时要特别注意
因为右操作数是一个逗号表达式(逗号表达式的结果为最后一项的值),再将逗号表达式的结果强转为Goods类型,调用一个参数的构造函数显式生成临时对象,再调用赋值运算符重载函数进行赋值
即good=(Goods)20;
而并非调用三个参数的构造函数显式生成临时对象,再调用赋值运算符重载函数进行赋值
运行结果: