Jaki jest pożytek z posiadania destruktora jako prywatnego?Jaki jest pożytek z posiadania destruktora jako prywatnego?
Odpowiedz
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ń".
Gdy nie chcesz, aby użytkownicy uzyskiwali dostęp do destruktora, tzn. Chcesz, aby obiekt został zniszczony tylko w inny sposób.
http://blogs.msdn.com/larryosterman/archive/2005/07/01/434684.aspx podaje przykład, w którym obiekt jest liczony jako odniesienie i powinien zostać zniszczony przez sam obiekt, gdy licznik zostanie wyzerowany.
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.
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;
}
Usunięcie należy wykonać za pośrednictwem znajomego/lub członka/ – MSalters
To już było wspomniane - więc pominąłem to. Czy uaktualnienia (w drugim czytaniu moje oświadczenie wygląda nieco zbyt mocno). – dirkgently
Korekta: Taki obiekt * może * zostać utworzony na stosie (ale tylko w zakresie znajomego lub samego siebie). –
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(){}
};
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.
Pouczające. Dzięki! –
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
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. –
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
}
zobaczyć guidline # 4 http://www.gotw.ca/publications/mill18.htm – Eric
Ten aswer brakuje jakiś przykład kodu. – mrgloom