C++ nontrival class 值传递的机制。

研究C++已经有一段时间了,我那时扔掉了手头的中文版c++ primer,开始阅读英文版,用时一年半多才勉强开完一遍,增加了一千一百多个注释,如果确认没有版权问题,我会把它共享。再给gcc提bug时,通过邮件交流得知C++标准化工作组的网站,http://open-std.org/JTC1/SC22/WG21/,后面有陆续接触了C++创始人写的书,以及他在自己home page http://www.stroustrup.com/发表的文章。也浏览Nicolai M. Josuttis关于标准库和template的书,并为其找到几处错误,还一直期待他的C++11 template相关的书籍。目前在研究GCC中C++标准库的实现,也在看lippman的 inside the c++ object model。


今天看到class作为函数参数传递的问题,解决了困扰自己很久的问题,回想起来,其实好多类似的问题,但我没有总结出来,尽管我水平不高,这些问题别人也可能碰到,总结出来总会帮助到别人的,后面我会慢慢回忆那些让我豁然开朗的情形,写出来。接下来进入正题。


在C++中,object有一种叫做memberwise的copy方式,函数参数传递就是用的这样的机制。对于类似int,char,或者c中的structure,这都不是问题,因为对于它们,memberwise copy实现的拷贝构造函数是合法的。大家都清楚,memberwise copy方式实现的拷贝构造并不总是合法的。那么如果memberwise copy不合法时,如何实现函数参数传递呢? 编译会采用下面的策略:

1、直接把作为参数的object构造在被调用的函数栈里

2、在calling function stack中构造函数参数,然后将called function parameter改写成引用形式。


GCC默认采用了第二种方式,下面是我用GDB验证的结果。


  1 #include <iostream>
  2 
  3 class test
  4 {
  5     private:
  6         int i;
  7     public:
  8         test(int v):i(v){}
  9         test(const test &v):i(v.i + 1){}
 10         virtual void show()
 11         {
 12             std::cout << i << std::endl;
 13             return;
 14         }
 15         ~test() = default;
 16 };
 17 
 18 int foo(test v)
 19 {
 20     int ii = 0;
 21     v.show();
 22     std::cout << ii << std::endl;
 23     return 0;
 24 }
 25 
 26 int main()
 27 {
 28     test v(1);
 29     foo(v);
 30     return 0;
 31 }


可执行程序gdb调式的结果


Breakpoint 1, foo (v=...) at how_class_argument_passed.cpp:20
20  int ii = 0;
(gdb) info r
eax            0xbffff588 -1073744504
ecx            0xbffff5b0 -1073744464
edx            0x2 2
ebx            0x48996000 1218011136
esp            0xbffff550 0xbffff550
ebp            0xbffff568 0xbffff568

esi            0x0 0
edi            0x0 0
eip            0x80486f2 0x80486f2 <foo(test)+6>
eflags         0x286 [ PF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb) print &v
$1 = (test *) 0xbffff588
(gdb) f 1
#1  0x08048773 in main () at how_class_argument_passed.cpp:29
29  foo(v);
(gdb) info r
eax            0xbffff588 -1073744504
ecx            0xbffff5b0 -1073744464
edx            0x2 2
ebx            0x48996000 1218011136
esp            0xbffff570 0xbffff570
ebp            0xbffff598 0xbffff598

esi            0x0 0
edi            0x0 0
eip            0x8048773 0x8048773 <main()+65>
eflags         0x286 [ PF SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0 0
gs             0x33 51
(gdb) print &v
$2 = (test *) 0xbffff580


可以看到函数foo的stack是0xbffff550 - 0xbffff568,但是值传递的参数地址是0xbffff588,明显不在foo stack中,在main stack中。

main stack 0xbffff570 - 0xbffff598,以及调用foo的argument的地址0xbffff580。

这说明调用foo时,参数是复制了,但是复制的object依然在主调函数的栈中。也就是上面说的第二种情况。





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值