boost shared_ptr的小技巧

 




这段代码有两个奇妙之处:

1. A的析构函数是protected,编译时并没有错误提示

2. A的析构函数不是virtual的,但最后B的析构函数却被调用了


shared_ptr真是让人眼前一亮,那就到boost的里面来探一探究竟吧


先从shared_ptr的申明开始:


 


注意到这里有两个变量, px, pn,来看看它们是怎么被申明的吧:


 


px与pn都是用p来做初始化的,px的类型就是模块参数T的指针, 但pn的类型还要再看一看:


 


而这个pi的定义是:


sp_counted_base * pi_;


从sp_counted_base类中可以看出,这就是引用计数的具体实现,对我们这里的问题没有任何意义,不过pi实际指向的对象sp_counted_impl_p却有些意思:


 


其中的px_申明为:


X * px_;



好了,把上面这结连起来看,问题就很清楚了。


在创建shared_ptr<X>对象时,内部实际上初始化了两个指针,一个是shared_ptr里的px,其值就是原始指针p,另一个是pn,在shared_count中可以看出来,其类型是p的实际类型,也就是说,p的实际类型与shared_ptr的模板参数类型X可以不一样,当然也只能是派生关系,否则也编译不过去。


放到最开始的例子中就是,px类型为A, pn内部类型为B。


其实在shared_ptr的构造函数中有这样一段注释:“Y must be complete”,也就是说原始指针的类型必须是完整的,因为这时编译器可以检查出指针的真正类型,并且在pn中记录下该类型,然后在释放的时候就可以调用正确的析构函数了。


但是如果在这里指针的类型就已经丢失了,那结果自然是不正确的,比如我们可以这样试一下:


 


当然,直接这样编译是通不过的,编译器会提示你A的析构函数是protected,对象无法被删除。是的,这就是问题所在了,此时传递给shared_ptr的参数类型已经是A了,pn中记录的指针类型也是A,所以他在删除该指针对象的时候也就只会调用A的析构函数,这时自然是通不过编译检查的。



然后再来看一看boost为什么要这样做,一个指针保存了两份,当然是有他的原因的。仔细看一下会发现,在对指针进行操作时使用的是shared_ptr内保存的px对象,而在删除指针时用的是pn内保存的指针。这样就很明白了,用模板参数类型的指针,一般也就是基类指针来调用方法,可以很好的支持多态,而使用原始类型的指针来做删除操作,这样又能保证对象被安全的删除。


Boost果然非常神奇。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值