2009-11-10 45 views
3

我偶然發現了一些我無法弄清楚的東西,所以我想我在更大的C++圖片中丟失了一些東西。確保指針不被刪除

總之,我的問題是:如何在一個類中保留一個可變的,不可刪除的,可能是NULL的對象實例。

較長的版本是:

我有以下情形:一堆類(我可以稍微改變,但沒有徹底重構),其中大部分需要使用的對象。這個對象雖然可變,但由其他人管理,所以不能刪除。

一些類中的一些類不需要這樣的對象 - 它們重用其他類中的代碼,但通過提供給這些類的可用參數可以保證,即使提供了對象,它也不會被使用。

當前實現使用指向const對象(const Obj *)。這反過來又意味着所有對象的方法必須是const的,而且大多數的字段都是可變的。這是一個混亂的解決方案,因爲聲明爲mutable的字段可用於檢查(與C++ lite條目here完全相反)。它也只部分地解決了「不要刪除這個在這裏」的問題(編譯器不會抱怨,但在對象前面的const是一個指示)。

如果我用了一個參考這個對象,我會迫使一些來電者創建一個「虛擬」的對象,並提供給他們實例化類。這也是一團糟,除了浪費資源。由於項目限制,我無法創建一個全局對象來代表「NULL」引用。

我覺得引用是我需要的工具,但是我不能重構涉及的類到這樣的程度,以至於讓對象從不使用它的實現中消失(它可以完成,但它不是簡單,它不會很快)。所以我想實現一些簡單的東西,如果有人試圖濫用這個對象,只會畫出一個警報信號,但會讓我的對象變爲可變的。

我能想到的最佳解決方案是使用常量指針到對象(Obj * const) - 這不會使編譯器抱怨,但我有我的可變對象和一種警報信號 - 通過const - 以及。

有沒有人有更好的主意?

回答

6

我歷來被這幾樣用一個shared_ptr/weak_ptr的組合實現的場景。見here.

所有者/缺失者會得到一個

boost::shared_ptr<T> 

你的類將得到一個

boost::weak_ptr<T> 

要重新分配弱PTR,只需重新分配指針:

void MyClass::Reassign(boost::weak_ptr<T> tPtr) 
{ 
    m_tPtr = tPtr; 
} 

要使用較弱的ptr,請首先檢查它是否仍然存在:

void MyClass::Use() 
{ 
    boost::shared_ptr<T> m_temporarySharedPtr = m_tPtr.lock(); 
    if (m_temporarySharedPtr) 
    { 
     //... 
    } 
} 

弱PTR可以通過正在重置,或將其分配給一個空的shared_ptr

void MyClass::MakeNull() 
{ 
    m_tPtr.reset(); 
} 
+0

我認爲這可能會起作用,而且看起來很簡單,我需要查看weak_ptr api以查看如何實現。 – laura 2009-11-10 13:49:01

+0

我已經接受了這個答案:這是一個介於這個和自己的包裝之間的過程,但有時候最好相信已建立的庫,而不是編寫自己的代碼。 – laura 2009-11-10 17:44:35

0

聽起來像一個shared_ptr的情況。

+1

不,它允許使用代碼檢索原始指針,並愉快地'刪除'它,因爲它想。 – 2009-11-10 12:08:36

+0

是的,因爲要做你認爲需要刻意編程的東西,這是不可能的,但總是有可能搞砸了,但是shared_ptr會阻止它意外發生 – Patrick 2009-11-10 14:16:35

6

可以使該對象私有的析構函數。這將在嘗試刪除對象時觸發編譯時錯誤。你也應該允許restcted代碼利用朋友機制或成員函數刪除對象。

+0

這很不幸被撤銷。我將不得不讓所有對象的朋友都成爲正確的用戶(他們很多都是)。此外,由於友誼和繼承的工作原理,我必須在每個派生的對象類中執行此操作。 – laura 2009-11-10 13:48:07

+3

您可以將一個非const方法添加到將使用私有析構函數刪除對象的類。任何可以訪問該方法的人都可以刪除該對象,除非他們獲得了const對象,在這種情況下他們不能調用該方法。 – Komat 2009-11-10 14:41:33

+0

但是,你必須給類const對象,這是不可變的。 – laura 2009-11-10 16:54:45

0

(如果允許你restircitons)的替代進行「空」是創建一個類似於虛擬對象到一個共享指針,充當所討論的對象和你的類之間的包裝。

你的類可以嘗試刪除這個對象,如果他們希望的話,但它本身會保持原始對象不變。重載*操作符,您可以透明地使用它。

+0

允許'刪除&(*包裝)'。 – 2009-11-10 12:19:35

+0

有時我討厭C++ ... :( – xan 2009-12-19 12:21:00

0

這樣的事情?......

obj的類是新類的集合,再指出其與Obj* cont pObj,其中建立了在創建新類的(或保留爲0如果它沒有被使用),那麼你在調用它的任何函數之前檢查pObj?

if (pObj){ pObj->foo(); } 

如果函數foo的錯誤定義爲可變的,那麼你需要解決它的聲明。

你的新類不負責清理/刪除Obj類。

+0

和...使Obj的析構函數私人 – timB33 2009-11-10 13:24:58

+0

你的Obj的不是一個單例嗎? – timB33 2009-11-10 13:37:40

1

你可以把一個包裝圍繞指針允許修改,但不刪除:

template <typename T> class Wrapper 
{ 
public: 
    Wrapper(T *p=0) : pointer(p) {} 

    T  *operator->()  {return pointer;} 
    T const *operator->() const {return pointer;} 
    operator bool()  const {return pointer;} 

private: 
    T *pointer; 
}; 

你可以使用這個就像一個指針,在某些情況下的模板類型,但不能調用刪除就可以了。包裝類型必須是structclass類型(即->有意義的類型)。然後使用,但不管理的生命週期的類之一,該物體看起來有點像這樣:

class User 
{ 
public: 
    void Assign(Object *o) {object = o;} 
    void UseObject() {if (object) object->Use();} 

private: 
    Wrapper<Object> object; 
}; 

從技術上講,你仍然可以得到的原始指針,但代碼做是非常錯誤的:

delete wrapper.operator->(); 
+0

我喜歡這個想法,但需要確切地看它涉及什麼。 weak_ptr之一,尤其是因爲我可以保證在我的類正在工作時從它的父對象中不銷燬對象 – laura 2009-11-10 13:52:27

+0

我已經添加了一些說明 – 2009-11-10 14:06:03

+0

shared_ptr和weak_ptr是好東西 - 如果您可以更改所有使用或管理對象使用它們。 – 2009-11-10 14:13:38