2012-08-12 72 views
1

我總是閱讀重寫智能指針行爲的新定義的可能性,但仍然今天我找不到一個真實的例子。如何重新定義/覆蓋智能指針的行爲和生命週期?

現在我想提出這個問題,看看我能得到一個解決方案:在添加新的狀態,可以

智能指針使用引用計數或引用鏈接來管理他們的壽命週期,我的基本問題包括導致釋放和刪除我的指針,我想在觸發事件時釋放我的資源。

這或多或少是在玩遊戲時,通常所有的資源都會在用戶從等級1傳遞到等級2時被加載和釋放,所以當這種情況發生時,等級1的資源將被釋放。我也想堅持這個例子,因爲你不能等待自動引用計數,也許認爲如果在級別2中沒有使用來自級別1的資源,它將被自動釋放,因爲它不再被請求;這可能是真實的,但是當用戶在壓力下使用機器時與內存一起操作是非常糟糕的舉動。

我想堅持使用智能指針,因爲我也對其提供的所有其他功能感興趣,但是他們對我有這個巨大的缺點,我需要直接管理他們的生命週期。

我有什麼選擇?

+0

如果您有一個「Level」對象,那麼在更改關卡時保留正確的對象將很容易。 – mfontanini 2012-08-12 01:07:08

+0

@mfontanini是的,但問題是如何釋放其他人,以及如何在等級發生變化並且不等待自動操作的同時執行此操作。 – user827992 2012-08-12 01:08:56

+0

觀察者模式如何? http://en.wikipedia.org/wiki/Observer_pattern – ForEveR 2012-08-12 01:13:43

回答

4

這聽起來像你剛纔扔了一堆共享指針,並沒有打擾正確的關於資源的所有權。從描述中我很清楚,關卡對象應該擁有所有這些資源。這意味着他們應該不被共享,因此根本不需要參考計數。

使用智能指針可以讓您免除在適當的時候手動釋放資源的負擔,但它並沒有讓您無法考慮適當的時間。

如果我是正確的,並且級別應擁有資源,請使用提供唯一所有權的智能指針,或者僅使用自動對象,甚至不用智能指針。除了需要訪問這些對象的級別以外的每個其他對象都需要一個非擁有指針或對它的引用,即傳統的指針或引用。

如果我錯了,應該確實共享資源,那麼當關卡被破壞時,它們不應該被釋放:其他共享所有權的對象不會喜歡它。

3

如果您在完成關卡之後仍有共享指針,這應該是由於共享指針未在關卡的生命週期內調用的函數堆棧上被分配爲自動變量,而是存儲在某種類型的容器或一系列全球可訪問的容器中。因此,您需要關心的主要問題是管理包含管理每個級別資源的共享指針的容器的生命週期。

例如,在函數foo內的堆棧上分配的智能指針只會具有與函數調用的持續時間相對應的生命期。一旦函數調用完成,共享指針就會被銷燬。如果還有額外的共享指針指向一個資源,那麼資源本身不會被銷燬,但是這些額外的共享指針需要駐留在被調用者堆棧以外的其他位置。所以你的工作就是管理那些「其他位置」,我猜測它們很可能是一系列全球可訪問的容器。

因此,沖洗每個級別的數據管理容器應該反過來徹底銷燬爲每個級別分配的資源。如果你願意,你可以使用一個事件驅動的接口或簡單的觀察者模式來觸發容器的刷新,或者它可以簡單地由析構函數明確地完成,該對象管理着關卡資源的生命週期。

最後,儘管它涉及到資源管理......只是因爲共享指針旨在防止內存泄漏並不意味着您不應該跟蹤它們如何或在何處分配。如果你集中存儲你的共享指針,那麼銷燬他們管理的資源並不是什麼大不了的事情。

2

這聽起來像你真的不應該使用共享指針。有許多方法可以通過指定自定義釋放器來覆蓋這些行爲,但我會考慮一種不同類型的「智能指針」。

Apache Web服務器使用內存池通過讓請求擁有一個內存池來釋放與請求關聯的所有資源。當您在服務器內分配內存時,您需要標識要從中分配的池。服務器維護一些內存池,每個內存池的生命週期不同 - 一個用於服務器實例,另一個用於該模塊,另一個用於每個請求等。這聽起來像是與您的情況更好的匹配。

Apache代碼使用它們的Apache Portable Runtime進行內存管理。它是用C語言編寫的,可能不是你所做的最佳匹配。它看起來像Boost有一個內存池庫,以及我從來沒有使用它。

3

如前所述,針對您的特定問題的共享指針可能不是正確的解決方案。但是,如果您想要分段釋放級別,您仍然可以手動管理其銷燬(或者,如果內存壓力不是太高或者存在問題,甚至可能稍後再等待一些備用CPU週期)。一旦你完成了一個資源,簡單地將它在一個全局隊列(或幾個隊列,可能每個類型或優先級等)中排隊銷燬。稍後簡單地處理該隊列並刪除引用。如果它確實是最後一個引用,則會觸發對象的銷燬。例如,您可以輕鬆地每隔幾個迭代就檢查一次計時器,並檢查一次您花費1ms釋放東西,退出並繼續下一幀。

性能明智,使用每個級別(或每個資產包)的內存池更有意義。它使內存管理變得更簡單,有時你可以一次性釋放整個池,並跳過內部所有對象的析構函數(如果你知道它們什麼都不做)。