当一个函数的形参为非const类型,而一个参数以非const传入,编译器一般会认为程序员会在该函数里修改该参数,而且该参数返回后还会发挥作用。
此时如果你把一个临时变量当成非const引用传进来,由于临时变量的特殊性,程序员无法对改临时变量进行操作,同时临时变量可能随时会消失,修改临时变量也毫无意义,因此,编译器规定:临时变量不能被“非const引用”绑定,即使我们不在函数中改变它,编译器也会报错。尤其临时变量存的值作为函数参数传入的时候,该函数参数表中相应的参数类型必须定义为const,否则报错error: cannot bind non-const lvalue reference of type xxxxxxxxxxxxx,报错原因比较隐蔽,debug困难。
下面是报错的代码:(截取部分相关的)
//大致是一个student类,有自定义的构造函数和拷贝构造函数
//代码报错于“使用构造函数定义对象数组”的代码行,但错误定位于“拷贝构造函数”那一块
student::student(char* in_str, float in_g1, float in_g2)
{
name = new char[strlen(in_str) + 1];
strcpy(name, in_str);
g1 = in_g1;
g2 = in_g2;
cout << "construct " << name <<endl;
}
student::student(student& in_obj) // 【问题所在】 参数不加const会报错
{
name = (char*)"liu";
g1 = in_obj.g1 - 10;
g2 = in_obj.g2 - 10;
cout << "copy " << name <<endl;
}
int main(){
student st[] = {student((char*)"zhang", 80, 70), student((char*)"wang", 90, 80)}; // error
//main函数中的其余部分省略
}
报错如下:
【分析】:
代码报错于“使用构造函数定义对象数组”的代码行,但错误定位于“拷贝构造函数”那一块。
报错的大致含义是:不能把非const的左值引用绑定到student类的右值上(“右值”指的是“只能读取不能被写”的变量,直观理解是“只能放在表达式右边的值”)。就是说:不能把非const的左值引用绑定到“只能读不能写的”(右值)对象上去(因为这样的绑定会使得可以通过引用来写右值rvalue对象)
奇怪的是我只是调用了构造函数来构造student类的对象数组,并没有主动调用拷贝构造函数(另外,我还尝试单独调用拷贝构造函数创建对象(而非对象数组)和构造函数创建对象(而非对象数组),均未报错)因此,应该是“定义对象数组”的过程中,自动调用了拷贝构造函数,并且在调用时违背了前文提到的“不能把非const的左值引用绑定到student类的右值上”的原则。
“对象数组”创建的过程中,内部实现如下:先初始化产生对象(此时就把各个对象赋值到相应的各个临时变量(临时对象)中存着),各对象初始化完成后,再把各个临时变量(临时对象)赋值给数组的各个[i]对象空间,完成对象数组的初始化。而这个“赋值”的过程,是“由对象产生对象”,就会调用拷贝构造函数,所以此时如果拷贝构造函数的参数不是const类型,那么把临时变量传进去,就会报错。
【总结】:
当定义对象数组并且在定义的同时完成初始化时,必须把 这个类的拷贝构造函数参数表中的那个引用参数 声明为const。