临时对象深入探讨、解析,提高性能手段[转]
临时对象的概念
int i = 1;
int &&r1 = i++; //r1和i之间没有什么关系。
//这个临时变量的生命周期与r1绑定了
r1 = 19;
i = 80;
- 另外一些临时对象,是因为我们代码书写问题而产生的,统一称临时变量为临时对象。
- new /delete处理堆上的问题,这里的临时对象基本属于栈的问题。
产生临时对象的情况和解决
1. 以传值的方式给函数传递参数
class CTempValue{
public:
int val1;
int val2;
public:
CTempValue(int v1 = 0, int v2 = 0);
CTempValue(const CTempValue& t) :val1(t.val1), val2(t.val2) //拷贝构造函数
{
cout << "调用了拷贝构造函数" << endl;
}
//拷贝赋值运算符
CTempValue & operator=(const CTempValue& tmpv){
val1 = tmpv.val1;
val2 = tmpv.val2;
cout << "调用了拷贝赋值运算符" << endl;
return *this;
}
virtual ~CTempValue() //析构函数
{
cout << "调用了析构函数" << endl;
}
public:
int Add(CTempValue ts); //普通函数
};
CTempValue::CTempValue(int v1, int v2) :val1(v1), val2(v2){
cout << "调用了构造函数" << endl;
cout << "val1 = " << val1 << endl;
cout << "val2 = " << val2 << endl;
}
int CTempValue::Add(CTempValue ts){
int tmp = ts.val1 + ts.val2;
ts.val1 = 1000; //这里修改值对外界没有影响
return tmp;
}
CTempValue tm(10, 20); //调用析构函数
int sum = tm.Add(tm); //这个会导致拷贝构造函数的执行
cout << "Sum =" << sum << endl;
cout << "tm.val1 =" << tm.val1 << endl;
int Add(CTempValue& ts); //普通函数
2 类型转换生成的临时对象/隐式类型转换以保证函数调用成功
CTempValue sum1;
sum1 = 1000; // 这里产生了一个真正的临时对象
- 分析:
- (1) 用1000这个数字创建了一个类型为CTempValue 的临时对象
- (2) 调用拷贝赋值运算符把这个临时对象里边的各个成员值赋值给了sum对象
- (3) 销毁这个临时创建的CTempValue对象。
- 优化写法:
CTempValue sum1 = 1000; //把定义对象和给对象初值放在一行上。
- 分析:
- 为sum1对象预留了空间,用1000构造sum1对象,而且是直接构造在sum1对象预留空间里。
隐式类型转换以保证函数调用成功
//统计字符ch在字符串strsource里出现的次数,把次数返回去
int calc(const string strsource, char ch){
//int calc(const string& strsource, char ch){
const char *p = strsource.c_str();
int icount = 0;
//.....具体的统计代码
return icount;
}
char mystr[100] = "I Love China, oh yeah!";
int result = calc(mystr, 'o'); //char[] 会转成临时string对象
- 如果上面函数参数改成: int calc(string strsource, char ch) , 也就是去掉const 就会编译报错。
- C++语言只会为const引用(const string & strsource)产生临时变量,而不会为非const引用(const引用 string & strsource)这种参数产生临时变量。
函数返回对象的时候
CTempValue Double(CTempValue &ts){
CTempValue tmpm; //这个会消耗我们一个构造函数和一个析构函数的调用
tmpm.val1 = ts.val1 * 2;
tmpm.val2 = ts.val2 * 2;
return tmpm;
}
- 分析 :
- Double()函数引起的消耗
- CTempValue tmpm; //会消耗一个构造函数和一个析构函数
- return tmpm; //产生临时对象,占用衣蛾拷贝构造函数和析构函数。
CTempValue ts1(10, 20);
Double(ts1); //因为返回临时对象导致占用了一个拷贝构造函数和一个析构函数。
//CTempValue ts3 = Double(ts1);
//CTempValue &&ts4 = Double(ts1); // 临时对象是一种右值
CTempValue Double(CTempValue &ts){
return CTempValue(ts.val1 * 2, ts.val2 * 2);
}
- 再举一例:介绍知识点:类外运算符重载。
- 类内:Time &Time::operator(const Time & tmpTime) {.... return *this };
- 类外示例:
class mynum{
public:
int num1;
int num2;
};
mynum operator+(mynum& t1, mynum & t2){
mynum result;
result.num1 = t1.num1 + t2.num1;
result.num2 = t1.num2 + t2.num2;
return result;
}
mynum operator+(mynum& t1, mynum & t2){
return mynum(t1.num1 + t2.num1, t1.num2 + t2.num2);
}