- 一、程序转化语义
- 1、显示的初始化操作
- 2、参数的初始化
- 3、返回值的初始化
- 4、在使用层面做优化
- 5、在编译器层面做优化
- 6、是否需要拷贝构造?
- 7、成员初始化
我们所写的代码,在内部是如何转换进行优化;1、显示的初始化操作
class X{};
X x0;
void foo_bar() {
X x1(x0);
X x2 = x0;
X x3 = X(X0);
}
会经过两个必要从程序转化阶段: - 重写每一个定义(占用内存的行为),其中的初始化操作会被剥除; - class的拷贝构造会被安插;2、参数的初始化
方法一:当一个类对象作为参数,会导入临时性的对象,并调用拷贝构造将其初始化,在将临时的对象交给函数,当离开函数时,将会调用其析构函数释放; 方法二:以拷贝建构方式,把实际参数建构在位置上,记录在堆栈中,在函数返回之前将其析构;
X xx; // X __temp0
// __temp0.X::X(xx);
foo(xx); // foo(__temp0);
3、返回值的初始化
返回值从局部对象中拷贝返回一般做一个双阶段转换: - 先加上一个额外参数(reference),用来放置拷贝建构的返回值; - 在return前插入拷贝构造调用的操作,将要返回的内容拷贝到reference中;
X bar() { // void bar(X& __result) 添加额外参数
X xx; // X xx;
// xx.X::X(); 默认构造
// __result.X::XX(xx); 拷贝构造
return xx; // return; 无返回值
}
void test(){
X xx = bar(); // X xx;
// bar(xx);
}
void test2() {
bar().memfunc(); // X __temp0;
// (bar(__temp0), __temp0).memfunc();
}
4、在使用层面做优化
21. 必须返回对象时,别返回reference
在这个条例上告诉我们如何将一个对象进行返回,效率会比较高;
X bar(const T& y, const T& z) { // void bar(X &__result)
return X(y, z); // __result.X::X(y, z); // 通过计算,而不是拷贝构造而得来的
// return;
}
5、在编译器层面做优化
编译器将result参数取代named return value(NRV); 该优化能大大的提供程序效率,但由于时编译器完成,故不能明确知道是否有被优化,且当函数较为复杂时,也难以被优化;
X bar() { // void bar(X& __result)
X xx; // 默认构造被调用 __result.X::X()
// 拷贝__result....
return xx;
}
6、是否需要拷贝构造?
class Point3d {
public:
Point3d(float x, float y, float z);
private:
float _x, _y, _z;
};
根据以上的情况下,由于没有【1.类成员2.基类3.虚基类4.虚函数】带有拷贝构造;故在此情况下对成员进行bitwise copy即可; 如果类需要大量的memberwise操作,那么我们需要提供一个explicit inline的拷贝构造;
Point3d::Point3d(const Point3d& rhs) {
// 扩张 __vptr__Point3d = __vtbl__Point3d; 若有虚函数
memcpy(this, &rhs, sizeof(Point3d));
}
但使用memcpy()还是memset(),只有在类内不含任何由编译器产生的内部成员时才会有效运行;否则将会导致成员初值被改写;7、成员初始化
4. 确定对象被使用前已先被初始化
class Word {
private:
string name;
int val;
public:
Word() : name(0) {
// name.string::string(0);
}
};



