2012-09-17 24 views
1

我有有一個指針指向B類作爲它的一個字段A類:通過傳遞一個外部指針或內部調用new構造的類,我可以天真地刪除這個指針在銷燬?

class A { 
private: 
    B *ptr; 
public: 
    A(B*); 
    A(); 
    ~A(); 
} 

A::A(B *ptr) 
{ 
    this->ptr = ptr; 
} 

A::A() 
{ 
    this->ptr = new B(); 
} 

A::~A() 
{ 
    delete this->ptr; 
} 

我想析構函數刪除只有B,如果它是由新的分配,我只能通過具有標誌做到這一點這是設置存儲指針的起源(這樣,只有在構造A期間分配ptr時纔會調用刪除),還是有更優雅的解決方案,即我可以在任何指針上調用delete(我知道如果傳入的指針是使用new分配的,它也會被刪除,但是如果指針從A的構造函數被調用的範圍傳入,顯然刪除它是未定義的)?

+5

沒有優雅的解決方案。你只需要記錄誰擁有指點物。如果'A'擁有它,那麼永遠不會傳遞一個指向自動分配的'B'的指針,但是由調用者來確定。 – juanchopanza

+1

歡迎來到爲什麼你永遠不應該使用原始指針的原因! –

+0

+1 @juanchopanza - 我不明白爲什麼有人想要/需要傳入並存儲一個指向任何可能具有比構造的對象更少的生命週期的指針,並且也可能被對象驅動器破壞。任何人都可以提出爲什麼可以這樣做嗎?當然,無論這個物體是否擁有它,或者沒有。 –

回答

3

還是有一個更優雅的解決方案

不,不是真的;需要清楚地記錄誰擁有這個指針。它看起來像你的班級,所以你可以自己構造ptr

#include <memory> 

class A { 
private: 
    std::unique_ptr<B> ptr; 
public: 
    A(some_data args) 
     : ptr(new B(args)) { }; 
    A();  
} 

如果你的類沒有自己的指針也沒關係,只是不要釋放它。否則,你需要在外部設置一個標誌(即dealloc_on_destruct)以知道該怎麼做,這可能會變得混亂。

+0

+1,我剛剛寫了一個類似的解決方案。 – juanchopanza

3

更優雅的解決方案是沒有擁有不同所有權模式的類,在這種情況下擁有vs不屬於您的類。不要將這兩個想法混合在同一個類中,因爲它只會混淆用戶/客戶(通過違反最小驚喜的原則)。

可以根據需要使用不同的行爲創建單獨的類,也可以選擇所有權模型並強制客戶堅持使用它(要麼傳入所有權,要麼轉移非默認構造函數中的所有權,分配)。

1

這個問題不能用你提供的代碼來回答。真正的問題是爲什麼你可以接受一個指針或者沒有,並且如果一個指針傳給你,誰擁有內存。

根據你的對象應該在你的特定領域做什麼,然後有不同的選擇可以採取。例如,如果您可以與主叫方共享所有權,那麼您應該採取shared_ptr,如果您要保留對象中的所有權,則應使用unique_ptr在界面中明確指出您的對象將獲取所有權。如果所有權不被共享,則考慮通過一個參考對象(即使在內部你存儲一個指針),在這種情況下,你可以實際使用單獨的所有權:

從什麼大家
// option 1: shared ownwership 
class A { 
    std::shared_ptr<B> ptr; 
public: 
    A(std::shared_ptr<B> const & p) : ptr(p) {} 
    A() : ptr(std::make_shared<B>()) {} 
}; 
// option 2: grab ownership 
class A { 
    std::unique_ptr<B> ptr; 
public: 
    A(std::unique_ptr<B> p) : ptr(std::move(p)) {} 
    A() : ptr(new B(); } 
}; 
// option 3: no ownership (unless we create the object) 
// (separating concerns: ref to access the object, ptr to manage it) 
class A { 
    std::unique_ptr<B> ptr; // only ownership 
    B * ref; 
public: 
    A(B & b) : ptr(), ref(&b) {} 
    A() : ptr(new B()), ref(ptr.get()) {} 
    // Internally use 'ref' to access the object the destructor will delete it 
    // if needed 
}; 
1

除了其他人說(避免這種設計):如果你完全無法避免這種設計,並且你需要擁有這個有趣的類,它有時擁有它的B,有時不需要,它取決於哪個構造函數被調用,那麼你可以使用unique_ptr(或shared_ptr),像這樣:

void delete_it(B*) { std::default_delete<B>()(t); } 
void do_nothing(B *t) {} 

class A { 
    unique_ptr<B, void(*)(B*)> ptr; 
    public: 
    A(B *ptr) ptr(ptr, do_nothing) {} 
    A() ptr(new B(), delete_it) {} 
    // no need for destructor 
    // hence also no need to worry about copy constructor or assignment 
}; 

它比更好的原因「原始指針加上一個標誌」是你避免必須實現刪除和複製(並在C++ 11中移動)。它可能比「原始指針加一面旗幟」表現更差,但大多數時候你不需要擔心這一點。如果合理,你可以回來做額外的工作。您不需要更改要切換的類的源接口,但它可能會破壞二進制兼容性。