2009-04-10 91 views
2

我正在尋找一種合適的方式來清理我的指針。 下面的示例代碼:C++多態不支持指針指針

class Parent { 
    protected: 
     int m_Var; 
    public: 
     Parent() : m_Var(0) {} 
     virtual ~Parent() {} 
     void PubFunc(); 
}; 

class Child : public Parent { 
    protected: 
     bool m_Bool; 
    public: 
     Child() : m_Bool(false) {} 
     virtual ~Child() {} 
     void ChildFunc(); 
}; 

void RemoveObj(Parent **ppObj) 
{ 
    *ppObj->PubFunc(); 
    delete *ppObj; 
    ppObj = NULL; 
} 

int main() 
{ 
    Parent* pPObj = NULL; 
    Child* pCObj = NULL; 
    pPObj = new Parent(); 
    pCObj = new Child(); 

    RemoveObj(&pPObj); 
    RemoveObj(&pCObj); // This is line 33 
    return 1; 
} 

但是編譯器會發出錯誤:

classes.cpp:33: error: invalid conversion from ‘Child**’ to ‘Parent**’ 
classes.cpp:33: error: initializing argument 1 of ‘void RemoveObj(Parent**)’ 

回答

12

有洙許多方法來正確處理內存。

的一個接近你的例子是:

template <typename T> 
RemoveObj(T **p) 
{ 
    if (p == NULL) return; 
    delete *p; 
    *p = NULL; 
} 

另外,你可能想使用std :: auto_ptr的替代。它看起來像:

int main() 
{ 
    std::auto_ptr<Parent*> pPObj(new Parent); 
    std::auto_ptr<Child*> pCObj(new Child); 
    // no deletes needed anymore 
+0

關於第一個解決方案:什麼是比較完善: 無效RemoveObj(無效** ppObj) – To1ne 2009-04-10 08:02:51

+0

第一個建議編譯和作品。 void RemoveObj(void ** ppObj)可以被定義,但如果你嘗試調用它,你的調用應該不會被編譯。 – 2009-04-10 08:09:11

+0

@ To1ne:我認爲刪除void *實際上是未定義的。使用模板解決方案,您有一個正確的靜態類型。應該爲void *調用什麼非平凡的析構函數? – 2009-04-10 08:09:21

1

您可以找到該書< C++常識>項目8指向指針的指針一些有用的信息。

2

你不需要爲刪除的包裝,保持簡單:

int main() 
{ 
    Parent* pPObj = NULL; 
    Child* pCObj = NULL; 
    pPObj = new Parent(); 
    pCObj = new Child(); 

    delete pPObj; 
    delete pCObj; // This is line 33 
    return 1; 
} 

記住你會遇到刪除數組類型的對象有問題,你RemoveObj(因爲你總是使用標delete)。另一種方法是通過一面旗子來表明你想要delete []。但正如我所說:KISS。

3

說得簡單:

孩子是父母的一個子類,所以這意味着兒童*可與母公司*

兒童*被取代並非家長的一個子類*所以這意味着孩子**不能被父母代替**

「孩子」和「孩子*」不是相同的類型。

2

如果你的問題是處理內存和資源,最好的建議是完全忘記你的方法,並使用智能指針。 std :: auto_ptrboost :: shared_ptr將是一個起點。

如果你用智能指針保存所有的堆分配資源,你的代碼將更加健壯。

3

你需要做的是取消所有指向你剛刪除的對象的指針。指針的想法是將有多個指針存儲同一對象的地址。如果沒有,那麼沒有什麼理由使用裸指針,所以你試圖捕獲的模式並不是很有用 - 但是你離第一個嘗試這個模式的人很遠。正如其他答案所提到的,處理指針的唯一方法是仔細控制對它們的訪問。

你的問題的標題是絕對正確的!這有一個很好的理由。指針標識存儲特定類型對象的位置。指向指針的指針可讓您更改指針指向的對象。

void Foo(Parent **pp) 
{ 
    *pp = new OtherChild(); 
} 

Child類從Parent派生,所以做我的OtherChild類。假設編譯器允許你這樣做:

Child *c = 0; 
Foo(&c); 

您預期工作,但如果有,那麼我們現在有一個Child指針c,其實指向的OtherChild一個實例。誰說這兩種類型是兼容的?

同樣,這是一個非常頻繁的誤解 - 它在其他語言中反覆出現,尤其是關於C#中的List<Parent>List<Child>

0

可能是最簡單的解決方案,我發現:

#define __REMOVE_OBJ(pObj) RemoveObj(pObj); pObj = NULL; 

並調用這一個:

__REMOVE_OBJ(pPObj); 
    __REMOVE_OBJ(pCObj); 

但我真的不喜歡現在的自己......

0

從討論make shared_ptr not use delete

共享指針將確保您清理時你應該和你不能訪問被破壞的東西。此外,您可以專注並提供備用銷燬方法。

boost::shared_ptr<T> ptr(new T, std::mem_fun_ref(&T::deleteMe));