5

考虑一个小单元测试用例

struct A
{
   virtual void func(){}
   A& foo()
   {
     A *obj = reinterpret_cast<A*>(0xdeadbeef);
     return *obj; //1
   }
};

int main()
{
   A obj = obj.foo();
}

在线1上是实现定义/未指定,当我们通过引用返回时不会发生尊重,如果没有显式访问指向的对象,程序不会崩溃?

我和我的一位同事发生了争论,他提到编译器在大多数情况下会优化取消引用,obj因为我们通过引用返回它并且这段代码不会崩溃?

谢谢

4

1 回答 1

4

我在 MS VC8.0 中反汇编代码,发现更有趣的事情:

006D48D6  mov         dword ptr [ebp-8],ecx 
    A *obj = reinterpret_cast<A*>(0xdeadbeef);
006D48D9  mov         dword ptr [obj],0DEADBEEFh 
        return *obj; //1
006D48E0  mov         eax,dword ptr [obj] //2 
    }
006D48E3  mov         esp,ebp 
006D48E5  pop         ebp  
006D48E6  ret    

//2 显示只是将obj的地址作为返回值放入eax寄存器。

006D39FC  lea         ecx,[ebp-190h] 
006D3A02  call        A::foo (6A8C12h) 
006D3A07  push        eax  //3
006D3A08  lea         ecx,[ebp-190h] 
006D3A0E  call        A::A (6B89BEh)

eax 是 0xdeadbeef,并像临时局部变量一样推送到堆栈。比我们调用复制构造函数(这是微不足道的)。所有这些操作都只是传递地址(这是非法的,但程序不关心)。因为 A 结构没有任何绑定到特定对象的成员,如果没有,程序将不会尝试通过取消引用找到特定对象'不需要。所以这颗炸弹还没有发射。

        A *obj = reinterpret_cast<A*>(0xdeadbeef);
        A tmp ;
         temp = *obj;

即使这样也可以,因为 operator= 也是通过引用传递,实际上是传递地址。如果添加成员变量,它将失败,因为它会尝试查找和复制成员。

于 2013-05-09T08:03:29.627 回答