2.3 program transformation semantics 程序转化语义学

显式初始化操作

显式调用 copy constructor

参数初始化

X xparam = xarg;

void foo(X x0)	// 函数原型
X xx;
foo(xx);	// 调用函数

宏观上,局部实例x0通过memberwise方式将xx当作初值

// **************************** 编译器实现***********************************
X _temp;	// 编译器产生临时对象
_temp.X::X(xx); 	// copy constructor
foo(_temp); 	//重新改写函数调用操作。以便使用上述临时对象
// **************************************************************************

// 临时对象通过copy constructor设定初值,再以 bitwise 拷贝到x0这个局部实例中。
此时foo()声明也发生了改变,形参变成了引用

void foo(X& x0)

返回值初始化

X Bar()
{
    X xx;
    return xx;
}
Ⅰ、添加一个额外参数,类型是class object reference。该参数用来存放返回的值。
Ⅱ、return之前执行copy constructor操作,将要传回的值拷贝给上述引用对象。

//可能的代码
void Bar(X &__result)                 //额外的参数
{
    X xx;                             //剥离
    xx.X::X()                       //default constructor
    __result.X::X(xx);               //编译器产生的 copy constructor 操作
    return;
}

所以对于 Bar():
//看到的
X xx = Bar();

//可能实际的代码
X xx;	// 这里不用执行default constructor,因为之后仅仅用来拷贝存储返回数据的。
Bar(xx);

//看到的
Bar().MemberFunc()                   //MemberFunc() 为 class X 的 member function

//可能实际上的代码
X __temp0;                          //编译器会产生一个临时 object
(Bar(__temp0), __temp0).MemberFunc();	// Bar(__temp0); __temp0.MemberFunc();
// **************************如果程序声明了一个函数指针******************************
//看到的
X (*pf)();
pf = Bar;                          //pf 为 函数指针

//可能实际的代码
X (*pf)(X&)                        //实际此函数指针与该函数的真面目相同
pf = Bar;

Optimization at the User Level (在用户层面做优化)

X bar(const T &y, const T &z)
{
	X xx;
	//......以y、z处理xx
	return xx;
}
// 按照上述思路应该是这样的:
void bar(X& _result, const T &y, const T &z)
{
	X xx;
	//......以y、z处理xx
	__result.X::X(xx); 
	return;
}
// 事实上是这样的:
X bar(const T &y, const T &z)
{
	return X(y, z);
}
// 被转化成执行:
void bar(X& _result)
{
	_result.X::X(y,z);
	return;
}
// 好处:_result直接计算出来,避免了copy constructor 拷贝,效率高!

Optimization at the Compiler Level (在编译器层面做优化)

像bar()这样的函数,所有的return指令传回相同的具名数值(named value),因此编译器有可能自己做优化,方法是以result参数取代named return value。例如 bar():

X bar()
{
	X xx;
	//...处理xx
	return xx;
}

用 _result 替代 xx:称为 Named Return Value(NRV)优化

void bar(X& __result)
{
	__result.X::X();	// 调用 default constructor
	//...直接处理__result
	return;
}

eg:

class X
{
	friend X foo(double);
public:
	X(){ memset( array, 0, 100*sizeof(double) ); }
private:
	double array[100];
};
X foo(double val)
{
	X local;

	local.array[0] = val;
	local.array[100] = val;

	return local;
}
调用 foo() 1000 万次,每次都产生一个 X 对象,设置每个对象的成员数组#0和#99有初值
int main()
{
	for(int cnt = 0; cnt < 10000000; cnt++){ X t = foo(double(cnt)); }
	return 0;
}

由于缺少 copy constructor,无法进行 NRV 优化。在类中加上拷贝构造函数:
拷贝构造函数: 类名(类名& name){}

inline X::X( const X& t){ memcpy(this, &t, sizeof(X)); }

是否需要 copy constructor

如果一个类涉及 memberwise copy ,就要提供copy constructor的explicit inline函数。
若编译器提供 NRV ,出现返回局部对象,则可使用 NRV 优化,避免调用 copy constructor。

posted @ 2021-04-15 11:42  点|滴  阅读(6)  评论(0)    收藏  举报