构造函数语义学之程序转化语义学(1)

大家知道初始化与赋值是有区别的,那么有哪几种初始化的方式呢?有以下三种情况://这句话可能有问题,回头修改!

  (1).明确的初始化操作(Explicit Initialization)

  (2).参数的初始化(Argument Initialization)

  (3).返回值的初始化(Explicit Initialization)

  先来看(1)---明确的初始化操作,这种比较直觉,大家一看就知道是初始化!请看如下代码:

X x0;

void foo_bar()
{
    X x( x0 );  //定义了 x1
    X x = x0;  //定义了 x2
    X x = X( x0 ); //定义了 x3
    //...
}

  那么编译器会给此段代码如何转化呢?分为两个阶段:

  (a). 重写每一个定义,其中的初始化操作会被剥除。

  (b).class 的 copy constructor 调用操作会被安插进去。

  那么转化后的代码就会变成像下面这个样子:

//可能的程序转化
//C++weidamai 

void foo_bar()
{
    X x1;     //定义被重写,初始化被剥除
    X x2;     //定义被重写,初始化被剥除
    X x3;     //定义被重写,初始化被剥除     

    // 编译器安插 X copy construction 的调用操作
    x1.X::x( x0 );    
    x2.X::x( x0 );  
    x3.X::x( x0 );  
} 

  在看(2)---参数的初始化( Argument Initialization),这种初始化挺常见,只是大家不容易发现。请看如下代码:

    void foo( X x0 );   //若已知这个函数

    //下面这样的调用方式

    X xx;

    foo( xx );

  这种代码可能看出有初始化,但其实发生了 X arg = xx; arg 代表 foo 的参数, 而 arg 代表真真的参数值。也就是初始化了一个临时变量!伪代码类似如下:

       // C++ 伪代码

     // 编译器产生出来的暂时对象

    X __temp0;

    // 编译器对copy constructor 的调用

    __temp0.X::X( xx );

    // 重新该写函数调用操作,以便使用上述的暂时对象

    foo( __temp0  );

  大家看到 foo( __ temp0 );的时候肯定回想这不又还原了吗,不和 foo( xx ) ;一样了嘛?确实如此,但是编译器把 foo() 函数的声明也换了,改成了 void foo( X& x0) !!!其中,class X 中肯定有析构函数,他会在 foo() 函数完成之后被调用,对付那个暂时性的 object (上面的 __temp0 )。

  最后看(3)---返回值的初始化( Return Value Initialization),这种也比较容易发现,看如下代码:

    X bar()

    {

       X xx;

       // operation

       //return xx;

    }

    X =  bar();

  你可能会问 bar() 的返回值如何从局部对象 xx 中拷贝过来?有的编译器采用一个双阶段转化:

  a. 首先加上一个额外的参数,类型时 class object 的一个 reference。这个参数用来防止被“拷贝构建( copy constructed )” 而得的返回值。

  b. 在 return 指令之前安插一个 copy constructor 调用操作,一遍将欲传回的 object 的内容当做上述新增参数的初值。

  那么以上的代码就可能被转化下面这个样子:

    //函数转化以反映出 copy constructor 的应用

    // C++ 伪码

    void bar( X & __result )

    {

      X xx;

      //编译器产生的 default constructor 调用操作 

      xx.X::X();

      //处理 xx

      //编译器所产生的 copy constructor 调用操作

      __result.X::X( xx );

      return ;

    }

    接下来编译器必须转化么一个 bar() 调用操作,以反映其新的定义。

    X xx = bar();

    将被转为如下两步:

    X xx;

    bar( xx );

    而 bar().fun();类似的则被翻译为:

    X __temp0; //编译器会给你创建一个临时变量,then

    (bar ( __temp0 ), __temp0).fun();

    同样道理,如果声明了指针函数并用来指向 bar() ,那么函数指针也会被重新定义!

  编译器只是简单的做如上的转化吗?他们有时还会做更多的优化转化,且看接下来的 构造函数语义学之程序转化语义学(2)!

原文地址:https://www.cnblogs.com/zhuwbox/p/3420503.html