this指针探幽

    C++中有个this关键字,它是“指向本对象的指针”,并且“不占用对象内存空间”。那么this指针到底是什么东东?是不是一个普通指针?能否更改它的值?放在什么地方?能否取它的地址?

    在开始讨论之前,想像一下如果由你设计编译器,你会怎么实现this指针?一种可能的方案是在内存中维护一个“this指针链表”或“this指针池”,把程序中所有对象的地址保存起来。这种方案下this指针就是一个普普通通的指针,当然可以取地址,可以更改值。另一种方案是每次用到this指针时(如调用类函数时——之所以说“类函数”而不是“成员函数”,是为了强调“成员函数属于类而不属于对象,调用时要传入对象的地址”这一事实),直接取对象的地址并保存到一个寄存器中。这种方案下,取this指针的地址当然是无意义的,但是更改值呢?这个方案似乎暗示了可以在类成员函数内部更改传入来的this指针。

    C++标准并没有对此作出规定,两个都是可行的。一般来说编译器相关的东西讨论下去已经没有什么意义,除非对运行效率有影响,而这个this指针又是无关痛痒的,所以下文大可不看(我本人都觉得无聊)。

    我只用过VC,VC肯定是第二个方案,其他编译器就不得而知了,据说主流编译器都采用第二个方案,估计是基于效率和可行性方面的考虑。下面详细讨论VC的this指针实现,以及这种实现的相关问题。

1、为什么说VC采用的是第二个方案,以及这个方案如何把对象地址传给类成员函数。

设有类

class A

 {

 public:

  void foo(int& sum)

  {

   for (int i = 0; i < 100; i++)

          sum += num[i];

  };

 private:

  int num[100];

 };

在main()里:

 A a;

int n = 0;

a.foo(n);

这样的话,只要在这里下断点,运行,查看汇编,就可以看到编译器是怎样把 a 的地址传给A::foo()。Debug模式下,是:

 a.foo(n);

004113FA  lea         eax,[n]        // 把n的地址赋给eax

00411400  push        eax            // 把eax推入堆栈

00411401  lea         ecx,[a]        // 把a的地址赋给ecx

00411407  call        A::foo (41100Ah)     // 调用foo()

可见,调用类成员函数时,参数通过堆栈传递,对象地址通过寄存器ecx传递。这个规则不会随着编译模式而改变,Release版本(完全优化)如下:

 a.foo(n);

0040107D  lea         ecx,[esp+4]

00401081  push        ecx

00401082  lea         ecx,[esp+0Ch]

00401086  call        A::foo (401000h)

 可以看到,仅仅是把符号n、a换成地址,参数的传递协议的确没变。由于讨论Debug版本对这个话题意义不大,下面的讨论都是基于Release完全优化版本。此时可以把ecx看作this指针,取其地址当然毫无意义,但是更改其值呢?试着在a.foo(n); 后面加上__asm{inc eax};看看,即:

 a.foo(n);

 __asm{inc ecx};

 a.foo(n);

 反汇编是:

 a.foo(n);

0040107D  lea         ecx,[esp+4]

00401081  push        ecx

00401082  lea         ecx,[esp+0Ch]

00401086  call        A::foo (401000h)

__asm{inc ecx};

0040108B  inc         ecx                // 修改this指针的值

a.foo(n);

0040108C  lea         edx,[esp+4]

00401090  push        edx

00401090  lea         ecx,[esp+0Ch]      // 编译器重新取对象的地址,修改失效

00401094  call        A::foo (401000h)

 可见编译器把函数调用编译成一个原子操作,在类成员函数外部无法修改this指针的值,或者说这种修改并没有起到修改的效果,是无效的——修改this指针的值后,下一次调用类成员函数并不会传入错误的对象地址。

【未完待续】

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值