显示的初始化操作
已知有如下代码:
X x0
void foo_bar() {
X x1(x0); // 定义另了x1,x2,x3
X x2 = x0;
X x3 = X(x0);
}
上述必要的程序转化有两个阶段:
- 重写每一个定义,其中的初始化操作会被剔除
class
的copy constructor
调用操作会被安插进去
在明确双阶段转化后,foo_bar()
可能看起来像这样:
// 伪代码
void foo_bar() {
X x1; 定义重写,其中的初始化操作会被剔除
X x2;
X x3;
// 编译器安插X copy construction调用操作
x1.X::X(x0);
x2.X::X(x0);
x3.X::X(x0);
}
其中的:x1.X::X(x0)
就表现出对以下的copy constructor
的调用:X::X(const X& xx)
返回值的初始化
X bar() {
X xx;
return xx;
}
你可能会问bar()
的返回值如何从局部对象xx
中拷贝过来?
- 首先加上一个额外的参数,类型是class object的一个reference.
- 在return指令之前安插一个copy constructor调用操作,以便將欲传回之object的内容当作上述新增参数的初始值
// 伪代码
void bar(X& __result) { //加上一个额外参数
X xx;
// 编译器所产生的default constructor操作
xx.X::X();
// 编译器所产生的copy constructor操作
__resutl.X::XX(xx);
return;
}
在编译器层面做优化
class test
{
public:
friend test foo(double);
test() {
memset(array, 0, 100 * sizeof(double));
}
double array[100];
};
inline test::test(const test& t) {
memcpy(this, &t, sizeof(test));
}
test foo(double val) {
test local;
local.array[0] = val;
local.array[1] = val;
local.array[2] = val;
return local;
}
int main(int argc, char *argv[])
{
for (int cnt = 0; cnt < 10000000; cnt++){
test t = foo(double(cnt));
}
}
这个程序的第一个版本不能实施NRV优化,因为test class缺少一个copy constructor
。第二个版本加上`inline copy constructor:
inline test::test(const test& t) {
memcpy(this, &t, sizeof(test));
}
第三个批评则是从相反的方向出:
void foo() {
// 这里希望有个copy constructor
X xx = bar();
// 这里调用destructor
}
在此情况下,对称性被优化打破了;程序虽然比较快,却是错误的;
这样的需求在许多陈股息可能被征以严格的"效率税",例如:
X xx0(1024);
X xx1 = X(1024);
X xx2 = (X) 1024;
在第二行和第三行中,语法明显的提供了两个步骤初始化操作:
- 將一个临时性的object设以初值1024
- 將临时性的object以拷贝构造的方式作为
explicit object
的初始值
Copy Constructor:要还是不要?
已知如下坐标类:
class Point3d {
public:
Point3d{float x, float y, float z};
private:
float _x,_y,_z;
};
上述三个坐标成员是以数值来存储的,bitwise copy
既不会导致memory leak
也不会产生address aliasing
;
那么这个class
的设计者是否应该提供一个explicit copy constructor
?答案是否;因为编译器为你实施了最好的行为;
如果你被问及是否预见class
需要大量的memberwise
初始化操作,例如传值的的方式传回objects?如果答案是yes,那么提供一个copy constructor
的explicit inline
函数实例久非常合理;