這段**有兩個奇妙之處:
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物件時,內部實際上初始化了兩個指標,乙個是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果然非常神奇。
智慧型指標boost shared ptr
boost shared ptr簡介 boost shared ptr屬於boost庫,定義在namespace boost中,包含標頭檔案 include便可以使用。上篇boost scoped ptr中我們看到boost scoped ptr獨享所有權,不允許賦值 拷貝。而boost share...
5 智慧型指標boost shared ptr
boost shared ptr簡介 boost shared ptr屬於boost庫,定義在namespace boost中,包含標頭檔案 include便可以使用。上篇 智慧型指標boost scoped ptr 中我們看到boost scoped ptr獨享所有權,不允許賦值 拷貝。而boos...
5 智慧型指標boost shared ptr
boost shared ptr簡介 boost shared ptr屬於boost庫,定義在namespace boost中,包含標頭檔案 include便可以使用。上篇 智慧型指標boost scoped ptr 中我們看到boost scoped ptr獨享所有權,不允許賦值 拷貝。而boos...