深度探索C++对象模型<五>

Program Transformation Semantics

明确的初始化

考虑这样的显式定义:

1
2
3
4
5
6
7
8
X x0;

void foo_bar()
{
X x1(x0);
X x2 = x0;
X x3 = X(x0);
}

这里的定义会分两个阶段进行:重写定义和安插copy constructor。如下:

1
2
3
4
5
6
7
8
9
10
11
void foo_bar()
{
X x1;
X x2;
X x3;

//安插代码
x1.X::X(x0);
x2.X::X(x0);
x3.X:;X(x0);
}

参数的初始化

C++标准中要求的是,当把一个class object当做参数传入函数或者作为返回值时,会这样初始化:

1
2
3
4
5
6
X xx = arg;//arg是实参

void foo(X x0);

X xx;
foo(xx);

而编译器的优化技术有两种方法,一个是采用临时值,然后修改foo函数;另一个方法就是采用copy contruct的方式把实参直接构建在应该的位置上。

对于第一个方法,如下:

1
2
3
4
5
6
7
8
9
//产生临时对象

X _temp0;
_temp0.X::X(x0);

foo(_temp0);

//修改foo函数,变成穿引用
void foo(X &x0);

返回值的初始化

考虑这样的函数定义:

1
2
3
4
5
6
X bar()
{
X xx;
//...
return xx
}

那么,这个局部对象是如何返回的呢?编译器采用的是双阶段的转化.

  • 首先是添加一个引用参数,作为返回值;
  • 在return之前安插copy constructor的操作,以便将要传回的object作为初始值;

修改的代码如下:

1
2
3
4
5
6
7
8
void bar(X &__result)//额外参数
{
X xx;
xx.X:XX();

__result.X::X(xx);
return;
}

摘要

由于copy constructor的应用,编译器会对代码进行一定程度的优化。尤其是当函数以穿值的方式传回一个object时,编译器会对copy constructor进行优化,以一个额外的第一参数取代NRV。