C++基本函数的调用优化(构造、拷贝构造、赋值)
合理的函数可提升时间和空间的利用率
//Test1.h #include<iostream> using namespace std; struct ST { private: int a; short b; public: ST(int a=0, short b=0):a(a),b(b) { this->a = a; this->b = b; cout<<"Object was Built. "<<this<<endl; } ~ST() { cout<<"Object was Free. "<<this<<endl; } ST(const ST &t); ST& operator=(const ST &t); int Get_a(); }; ST::ST(const ST &t) { this->a = t.a; this->b = t.b; cout<<"Object was Copy. "<<this<<endl; } ST& ST::operator=(const ST &t) { cout<<"Assign:"<<this<<" = "<<&t<<endl; if(this != &t) { this->a = t.a; this->b = t.b; } return *this; } int ST::Get_a() { return this->a; }
#include<iostream> #include"Test1.h" using namespace std;
ST fun(ST t)
{
int value = t.Get_a();
ST tmp(value);
return tmp;
} void main() { ST t(12,13); ST t1(t); ST t2; t2 = fun(t); }
运行结果及分析①
1:对象t的构造和析构
2:对象t1的拷贝构造与析构
3:t2的构造与析构
ST fun(ST t) { int value = t.Get_a(); ST tmp(value); return tmp; }
4:fun()函数的参数为对象,调用拷贝构造函数创建临时对象,其在fun函数结束后被析构掉
5:fun()函数内使用ST实例化类tmp,其在函数结束后被析构掉
6:函数返回时调用拷贝构造函数创建一个临时对象,该对象在完成赋值后才被析构掉,所以6并不是tmp,这个临时对象可以生存到函数结束
运行结果及分析②
ST fun(ST t) { int value = t.Get_a(); return ST (value); }
改变的代码仅有fun()函数变化
1,2,3,4与相同,不再赘述
这里的改变是不再创造有名对象,而是直接返回一个无名临时对象,将①的5,6合二为一,所以返回时仅需要使用构造函数构造一个无名临时对象,
在赋值后被析构掉。省掉了①中的拷贝构造。
运行结果及分析③
ST fun(ST &t) { int value = t.Get_a(); return ST(value); }
与②相比,只改变了参数
1,2,3同上
当使用引用传递参数时,就不需要使用拷贝构造函数创建临时对象,将②的4省掉,③的4与②的4作用相同
运行结果及分析④
ST fun(ST &t)
{
int value = t.Get_a();
return ST(value);
}
void main() { ST t(12,13); ST t1(t); ST t2 = fun(t); }
这里与③的不同是将主函数修改
主函数内st2从先使用构造函数初始化,再赋值,变成了直接使用赋值为其初始化
在前面我们知道
ST t(1,2);
ST st;
st = t;
和
ST t(1,2);
ST st = t;
实例化st 的不同是 前者先构造再拷贝构造,后者只需要拷贝构造。
所以,主函数使用了上例子后者的写法,可以直接省去t2的构造,直接拷贝构造,但是关键问题就在这里,
由于fun()函数返回的对象是一个无名的临时对象,所以编译器直接让其初始化t2,而省去拷贝构造的过程。
总结
1.从②我们可以知道,函数使用无名临时对象作为返回值,比在函数内创建有名临时对象更快,更节省空间,提升效率。
2.从③我们可以看出来在函数参数为对象时,使用引用可以省掉拷贝构造。
3.从④可以知道,在使用对象对对象进行赋值时,直接使用拷贝构造时最快的方法。这同时也说明了,无名的临时对象有时候可以被当作中间变量,而不需要从头进行拷贝构造工作。