2010-11-16 47 views
6

我對shared_ptr有些疑惑。要使用shared_ptr,安全嗎?

說,我有類:

class foo { 
    int _f; 
}; 
typedef std::shared_ptr<foo> fooptr; 

class bar { 
    int _b; 
}; 
typedef std::shared_ptr<bar> barptr; 

class foobar : public foo, public bar { 
    int _fb; 
}; 

int main() { 

    foobar *fb1 = new foobar(); 
    foobar *fb2 = new foobar(); 

    fooptr f((foo *)fb1); 
    barptr b((bar *)fb2); 

    return 0; 
} 

因爲b.get()= FB2,所以應該崩潰,當程序退出?或者它是安全的?

回答

10

A shared_ptr<base>可以安全地取得derived*的所有權,即使base沒有虛擬析構函數。

但是,這隻有在shared_ptr知道該對象的最大派生類型是何時取得它的所有權時才起作用。如果你要刪除演員表

fooptr f(fb1); 
fooptr b(fb2); 

那麼你一定會好的。隨着鑄件,該shared_ptr無法知道對象的最底層派生類型是什麼,當它需要它的所有權,這樣的行爲是不確定的,就像你說的:

foo* f = new foobar(); 
delete f; 

的最好的事情是遵循"a base class destructor should be either public and virtual, or protected and nonvirtual."

+0

+1,你打我解釋模板的構造函數。 – 2010-11-16 15:32:41

+0

謝謝你的回覆:) – ddh 2010-11-16 15:53:05

0

foobar不是多態類,因此此代碼很可能會導致無效的指針釋放。

7

不,這不安全。 foobar需要虛擬析構函數,否則不確定當shared_ptr的析構函數刪除它所持有的指針時會發生什麼。當然,說這不安全與說它應該崩潰是不一樣的。

另外,有一些神奇[*]這意味着建成shared_ptr,如果你不投給foo*,你的代碼變得安全:

fooptr f(fb1); 
barptr b(fb2); 

要麼與虛擬析構函數,或者如果剔除在強制轉換時,當shared_ptr來刪除指針時,編譯器將「知道」如何將指針調整回原來的類型,以便調用正確的析構函數並釋放內存。

這個魔術只能用,因爲fb1foobar*,不過。如果沒有虛析構函數,下面仍然是不安全的:

foo *fb = new foobar(); 
fooptr f(fb); 

如果你使用shared_ptr這樣的,那麼就沒有這樣做的風險:

fooptr f(new foobar()); 

您還可以避免在代碼中的問題,如果第二次調用new foobar()引發異常,則第一個對象被泄漏。如果你要使用shared_ptr爲你管理內存,那麼你需要儘快獲得下管理存儲儘可能:

fooptr f(new foobar()); 
barptr b(new foobar()); 

現在,如果第二行拋出,f會得到妥善銷燬,並會刪除物體。

[*]「magic」=一個構造函數模板,它在shared_ptr中存儲一個函數指針,該函數將存儲的指針轉換回正確的類型,然後將其刪除。

+0

如果foo和bar都具有虛擬析構函數,那麼它是安全的嗎? – ddh 2010-11-16 15:29:04

+0

儘管如此,明確的轉換仍然存在,而且它是安全的,因爲'shared_ptr'有一個模板化的構造函數,它可以確保通過最初傳遞給構造函數的指針的類型進行銷燬,而不是'shared_ptr'的模板參數,破壞。在基類中有一個虛擬析構函數仍然是非常可取的;但這在技術上並不危險。 – 2010-11-16 15:30:25

+0

我認爲在shared_ptr的析構函數中,應該有「delete ptr」,並且delete的操作可以:1)調用對象的去零域,2)釋放內存。但是,如果所有內存都是0x10000,但shared_ptr得到的是0x10004,那麼應該有一些問題? – ddh 2010-11-16 15:30:53

-1

這是不安全的,因爲您在C++代碼中使用C風格轉換。

不要使用C風格的演員陣容,用蒙上如static_castdynamic_castconst_castreinterpret_cast。另外,沒有碰撞並不意味着安全。

事實上,在這種情況下只需移除鑄件。

+0

'dynamic_cast'拼寫'dynamic_cast',句點。 – curiousguy 2017-01-19 04:24:07