Jak zadeklarować i wywołać destruktor

0

Witam, mam klasę składającą się z takich oto konstruktorów i metod:

class WierszTrojkataPascala
{
    public:
        WierszTrojkataPascala(int n);
        int Wspolczynnik(int m);
        int Newton(int a, int b);
        ~WierszTrojkataPascala(int n);
        
    protected:

    private:
        int *tab;
};

Po pierwsze, czy destruktor dobrze zadeklarowałem, czy daje się go bez zmiennej już? Co należy umieścić w jej destruktorze i jak ją potem wywołać w main-ie? Czytałem gdzieś że wszystko co jest dynamiczne ma się znajdować, także dałem tylko tablicę do destruktora, ale czy nie można tam metod też umieścić?

3

Destruktor nie przyjmuje żadnych argumentów. Patrząc po definicji klasy, prawie z pewnością mogę stwierdzić, że łamiesz zasadę 3/5/0 (dlaczego ignorujesz rady i używasz nagich wskaźników?).

W destruktorze należy umieścić kod, który ma się wykonać podczas kończenia czasu życia obiektu. Może to być jakiś zapis do logów, może to być zwolnienie zasobów (zła praktyka, patrz wyżej na zasadę 3/5/0).

Destruktor wywoływany jest w momencie kończenia czasu życia obiektu. Najczęściej jest to okalający go }, o ile nie robisz jakichś dziwnych akrobacji, jak np. alokacja obiektów za pomocą new.

2

W sumie powtarzam to co @kq napisał, ale chcę podkreślić to co jest ważne.

Destruktor jest automatycznie wołany podczas zniszczenia obiektu. W 99% przypadków nie masz potrzeby i nie powinieneś go wołać ręcznie. Obiekt jest niszczony gdy wychodzi poza swój zakres w przypadku obiektów lokalnych (na stosie) lub gdy wołasz delete na wskaźniku wskazujący na obiekt na stercie.
Celem destruktora nie jest niszczenie obiektu, bo to jest robione automatycznie, lecz sprzątanie wewnętrznych danych obiektu. Jeśli trzymamy się zasady 0 to destruktor jest najczęściej pusty i nie trzeba go nawet deklarować, chyba że chcemy wirtualny to wtedy wystarczy

virtual ~NazwaKlasy() = default;
0

Mógłby ktoś przetłumaczyć o co w tej zasadzie chodzi? Nie jestem za dobry z angielskiego, a nic po polsku nie udało mi się o niej znaleźć.

0

Generalnie chodzi o to, że masz dążyć do tego, aby destruktorów nie musieć pisać w ogóle - tak samo konstruktorów i operatorów= kopiujących/przenoszących. Wszystkie operacje związane z zarządzaniem zasobami powinny być przeniesione do klas za to odpowiadających (np. unique_ptr).

Reguła 3 mówi, że jeśli definiujesz dowolne z następujących: destruktor/operator= kopiujący/konstruktor kopiujący, to musisz zdefiniować pozostałe. Reguła 5 dorzuca jeszcze dodane w C++11 konstruktor i operator= przenoszące.

1

A reguła zera mówi, że regułę trzech czy pięciu powinny implementować tylko kontenery, smart pointery i tem podobne, a większość własnych klas nie powinna mieć żadnego z tych 3 czy 5 elementów (czyli przede wszystkim nie mieć jawnego destruktora).
Zarządzanie zasobami odbywa się wtedy wyłącznie w klasach ściśle do tego przeznaczonych.

Przykładowo, zamiast int *tab w klasie i przydzielania pamięci w konstruktorze a zwalniania w destruktorze, a do tego odpowiednio oprogramowanego konstruktora i operatora kopiującego, lepiej dać vector<int> tab, przydzielić pamięć w konstruktorze, a o destruktorze i reszcie zapomnieć. Pamięć się zwolni prawidłowo, bo vector ma swój destruktor.

Ja bym dodał jeszcze “rule of one”, ale nie każdemu się to spodoba: można zaimplementować destruktor jednocześnie zakazując kopiowania takiego obiektu (operator i konstruktor kopiujący z dodanym =delete).
Ma to sens zwłaszcza jeśli zasobem nie jest pamięć, tylko np. połączenie sieciowe i nie chcemy się zastanawiać co miałoby właściwie oznaczać „skopiowanie połączenia”.

1 użytkowników online, w tym zalogowanych: 0, gości: 1