2009-03-10 11 views

Odpowiedz

139

Zasadniczo za każdym razem, gdy chcesz, aby inna klasa była odpowiedzialna za cykl życia obiektów twojej klasy, lub masz powód, by zapobiec zniszczeniu obiektu, możesz uczynić destruktor prywatnym.

Na przykład, jeśli robisz coś w rodzaju liczenia odwołań, możesz mieć obiekt (lub menedżera, który był "przyjacielem" ed) odpowiedzialny za zliczanie liczby odniesień do siebie i usunąć go, gdy liczba uderza zero. Prywatny dtor uniemożliwiłby komukolwiek usunięcie go, gdy wciąż byłyby do niego odniesienia.

Dla innej instancji, co jeśli masz obiekt, który ma menedżera (lub siebie), który może go zniszczyć lub może odmówić jego zniszczenia w zależności od innych warunków w programie, takich jak połączenie z bazą danych jest otwarte lub plik być napisanym. Możesz mieć metodę "request_delete" w klasie lub menedżera, która sprawdzi ten warunek, a następnie usunie lub odrzuci i zwróci status informujący o tym, co zrobił. To znacznie bardziej elastyczne niż po prostu "usuń".

+3

zobaczyć guidline # 4 http://www.gotw.ca/publications/mill18.htm – Eric

+2

Ten aswer brakuje jakiś przykład kodu. – mrgloom

5

Klasę można usunąć tylko samodzielnie. Przydatne, jeśli tworzysz próbę odniesienia zliczonego obiektu. Wtedy tylko metoda zwolnienia może usunąć obiekt, prawdopodobnie pomagając uniknąć błędów.

55

Takiego obiektu nigdy nie można utworzyć na stosie. Zawsze na kupie. Usunięcie należy wykonać za pośrednictwem znajomego lub członka. Produkt może wykorzystywać jedną hierarchię obiektów i niestandardowy menedżer pamięci - takie scenariusze mogą korzystać z prywatnego dtor.

#include <iostream> 
class a { 
    ~a() {} 
    friend void delete_a(a* p); 
}; 


void delete_a(a* p) { 
    delete p; 
} 

int main() 
{ 
    a *p = new a; 
    delete_a(p); 

    return 0; 
} 
+1

Usunięcie należy wykonać za pośrednictwem znajomego/lub członka/ – MSalters

+0

To już było wspomniane - więc pominąłem to. Czy uaktualnienia (w drugim czytaniu moje oświadczenie wygląda nieco zbyt mocno). – dirkgently

+12

Korekta: Taki obiekt * może * zostać utworzony na stosie (ale tylko w zakresie znajomego lub samego siebie). –

2

To może być sposobem radzenia sobie z tym problemem w systemie Windows, gdzie każdy moduł można wykorzystać inny kupa, takie jak Debug sterty. Jeśli ten problem nie zostanie poprawnie obsłużony, może się zdarzyć badthings.

3

Wiem, że pytałeś o prywatnego destruktora. Oto, w jaki sposób korzystam z chronionych. Pomysł polega na tym, że nie chcesz usuwać głównej klasy przez wskaźnik do klasy, która dodaje dodatkową funkcjonalność do głównej.
W poniższym przykładzie nie chcę, aby GuiWindow został usunięty za pomocą wskaźnika HandlerHolder.

class Handler 
{ 
public: 
    virtual void onClose() = 0; 
protected: 
    virtual ~Handler(); 
}; 

class HandlerHolder 
{ 
public: 
    void setHandler(Handler*); 
    Handler* getHandler() const; 
protected: 
    ~HandlerHolder(){} 
private: 
    Handler* handler_; 
}; 

class GuiWindow : public HandlerHolder 
{ 
public: 
    void finish() 
    { 
     getHandler()->onClose(); 
    } 

    virtual ~GuiWindow(){} 
}; 
15

COM używa tej strategii do usuwania instancji. COM sprawia, że ​​destruktor jest prywatny i zapewnia interfejs do usuwania instancji.

Oto przykład tego, jak powinna wyglądać metoda Release.

int MyRefCountedObject::Release() 
{ 
_refCount--; 
if (0 == _refCount) 
{ 
    delete this; 
    return 0; 
} 
return _refCount; 
} 

Obiekty ATL COM są doskonałym przykładem tego wzoru.

+0

Pouczające. Dzięki! –

3

dirkgently jest źle. Oto przykład obiektu z prywatnym c-tor i d-tor utworzonym na stosie (używam tu funkcji statycznego członka, ale można to zrobić również za pomocą funkcji friend lub friend).

#include <iostream> 

class PrivateCD 
{ 
private: 
    PrivateCD(int i) : _i(i) {}; 
    ~PrivateCD(){}; 
    int _i; 
public: 
    static void TryMe(int i) 
    { 
     PrivateCD p(i); 
     cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl; 
    }; 
}; 

int main() 
{ 
    PrivateCD::TryMe(8); 
}; 

Kod ten będzie produkować wyjście: wewnątrz PrivateCD :: TryMe, p._i = 8

+2

Jestem prawie pewny, że oznacza to, że kod, który * używa * twojej klasy, nie może utworzyć instancji klasy na stosie. Oczywiście nadal można utworzyć instancję klasy na stosie * w ramach metod * klasy, ponieważ w tym kontekście można uzyskać dostęp do prywatnych członków. –

5

Dodawanie do odpowiedzi już tu obecna; prywatne konstruktory i destruktory są całkiem przydatne przy implementacji factory, gdzie wymagane obiekty muszą być przydzielone na stercie. Obiekty byłyby generalnie tworzone/usuwane przez statycznego członka lub przyjaciela. Przykładem typowego użytkowania:

class myclass 
{ 
public: 
    static myclass* create(/* args */) // Factory 
    { 
     return new myclass(/* args */); 
    } 

    static void destroy(myclass* ptr) 
    { 
     delete ptr; 
    } 
private: 
    myclass(/* args */) { ... }   // Private CTOR and DTOR 
    ~myclass() { ... }     // 
} 

int main() 
{ 
    myclass m;       // error: ctor and dtor are private 
    myclass* mp = new myclass (..);  // error: private ctor 
    myclass* mp = myclass::create(..); // OK 
    delete mp;       // error: private dtor 
    myclass::destroy(mp);    // OK 
}