程序转化
拷贝构造函数,就是用一个已存在的对象去初始化另一个对象。
那么,以下三种情况,显然需要用到拷贝构造函数。
// 对象t2 初始化 对象t1
TestCls t1;
TestCls t2 = t1;
// 函数实参对象t 初始化 函数形参对象temp
void fun1(TestCls temp){
return;
}
TestCls t;
fun1(t);
// 函数返回值对象temp 初始化 对象t
TestCls fun2(){
TestCls temp;
return temp;
}
TestCls t = fun2();
因此,这三种情况,会迫使编译器对用户代码进行部分转化,在适当的位置插入对拷贝构造函数的调用。
编译器转化后的代码可能如下:
// 情况一
TestCls t1;
TestCls t2;
t2.TestCls::TestCls(t1); // 调用拷贝构造函数
// 情况二
void fun1(TestCls temp){
return;
}
TestCls t;
TestCls temp; // 引入临时性变量,承接实参
temp.TestCls::TestCls(t); // 调用拷贝构造函数
fun1(temp);
// 情况三
void fun2(TestCls &result){ // 添加额外参数,承接返回值
TestCls temp;
temp.TestCls::TestCls(); // 调用默认构造函数
result.TestCls::TestCls(temp); // 调用拷贝构造函数
return;
}
TestCls t;
fun2(t);
NRV优化
如果能去掉这些拷贝构造函数,那该有多好。
显然,编译器也考虑到了这点。所以有时候,编译器会默默地自己进行 NRV 优化。
编译器会在拷贝构造函数中,用额外参数 _result 来替换有名字的返回变量(Named Return Value),本例中即为 temp。
void fun2(TestCls &result) {
// 不用先构造 temp,再用 temp 拷贝构造 _result
// 直接构造 _result
_result.TestCls::TestCls();
return;
}