对于临时变量经常会有一个误解,就是将仅仅需要一小段时间的变量称为临时变量:
template<typename T>
void swap(T& obj1, T& obj2)
{
T temp = obj1; //误解为temp是临时变量,其实正确地说temp是一个局部变量
obj1 = obj2;
obj2 = temp;
}
在C++中真正的临时变量是看不见的,它们不出现在源代码中。通常建立一个没有命名的非堆对象会产生临时对象。这种未命名的对象通常在两种条件下产生:
1)编译器为了使函数成功调用而进行的隐式类型转换;
2)函数返回对象时。
我们之所以关系临时变量,是因为构造和析构它们的开销对于程序的性能来说有着不可忽视的影响。
情况一:使函数成功调用而建立的临时对象:
当传送给函数的对象类型与参数类型不匹配时会产生这种情况:
//返回ch在str中出现的次数
size_t countChar(const std::string& str, char ch);
char buffer[MAX_STRING_LEN];
char c;
//读入到一个字符和字符串中,用setw避免缓存溢出,当读取一个字符串时
std::cin>>c>>setw(MAX_STRING_LEN)>>buffer;
std::cout<<"There are "<<countChar(buffer, c)
<<" occurrences of the character "<<c
<<" in "<<buffer<<std::endl;
如上代码所示,传入countChar函数的第一个参数是字符数组,但该函数接受的是const std::string&类型的参数。此时编译器会建立一个std::string类型的临时对象,通常是以buffer数组作为参数调用std::string的构造函数来初始化这个临时对象。之后countChar的参数str被绑定在这个临时的std::string对象上;当countChar返回时,临时对象自动释放。
我们发现,仅当函数通过传值方式传递对象或者传递常量引用(const &)参数对象时,编译器才会自动进行这样的类型转换。当传递一个非常量引用参数对象时,就不会发生。例如:
void uppercasify(std::string& str); //注意这里是非常量引用(没加const)
char message[] = "See you in another life brother!";
uppercasify(message); //编译错误
编译器编译不通过的原因是:假设建立一个临时对象,那么临时对象将被传递到uppercasify中,这只会修改这个临时对象,但是对函数真正的参数message没有任何影响。因此,C++语言禁止为非常量引用产生临时对象,编译自然就通不过了!
情况二:函数返回对象时:
const Number operator+(const Number& nm1, const Number& nm2);
这个函数的返回值是临时的,因为它没有被命名:它只是函数的返回值。因此我们必须为每次调用operator+构造和释放这个临时对象而付出开销。
综上:临时对象是有开销的,应该尽可能去除它们。在任何时候只有见到常量引用参数(const &),就存在建立临时对象而绑定在函数参数上的可能性;任何时候只要见到函数返回对象,就会有一个临时对象被建立(以后被释放)。