• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

czy destruktor jest mi potrzebny czy nie?

Object Storage Arubacloud
0 głosów
145 wizyt
pytanie zadane 30 marca 2020 w C i C++ przez Quegon23 Nowicjusz (150 p.)
#include <iostream>
using namespace std;

/*
    - Klasa A skłąda się z tablicy, która przechowuje pojedynczy ciąg jednego z dwóch znaków 'A' i 'B' o rozmiarze length
    - Konstruktor w, którym alokujemy dynamicznie pamięć oraz wybieramy poprzez liczbe jakie mamy zamiar znaki wstawić
    - Destruktor do zwalniania pamięci
    - Metoda getvar() do wydobywania tablicy
*/

class A
{
    private:
        char* var;      // łańcuch znaków
        int length;     // długość znaków

    public:
        A(int number, int length)   //Konstruktor
        {
            this -> length = length;
            this -> var = new char[this -> length];

            if(number == 0)
                for(int i=0; i<this -> length; i++)
                    var[i] = 'A';

            else
                for(int i=0; i<this -> length; i++)
                    var[i] = 'B';
        }
        ~A(){ delete var; } //destruktor
        char* getvar(){ return this -> var; }
};

/*
    - Klasa B składa się ze statycznej tablicy znaków, która ma za zadanie doklejac
    różne wybrane przez użytkownika sekwencje tablicy z poprzedniej klasy
    - Metoda show() wyświetla na ekran tablice
    - Destruktor zwalnia pamiec tablicy
    - Metoda Change() jest tu cały zaimplementowany mechanizm wklejania z tablicy w klasie A do tablicy w klasie B

*/

class B
{
    private:
        static char* vars;
        static int size_vars;

    public:
        static void show()
        {
            for(int i=0; i<size_vars; i++)
                cout << vars[i] << " : ";
        }
        void change(char* v, int n)
        {
            //Alokacja bufora pamięci
            char* new_var = new char[size_vars + n];

            //kopiowanie aktualnej tablicy do bufora
            for(int i=0; i<size_vars; i++)
                new_var[i] = vars[i];

            //dodawanie nowych znaków do bufora
            for(int i=size_vars; i<size_vars+n; i++)
                new_var[i] = v[i-size_vars];

            //zwolnienie pamieci starej tablicy
            delete[] vars;

            //zwiększenie rozmiar
            size_vars = size_vars + n;

            //Alokacja nowej statycznej tablicy
            vars = new char[size_vars];

            //kopiowanie z bufora do nowej tablicy
            for(int i=0; i<size_vars; i++)
                vars[i] = new_var[i];

            //zwalnianie bufora
            delete[] new_var;
        }
        ~B(){ delete[] vars; }
};

char* B::vars = A(0,3).getvar();
int B::size_vars = 3;

int main()
{
    B b;
    b.show();
    cout << endl << endl;
    char* tab = A(1,5).getvar();
    b.change(tab,5);
    b.show();


    return 0;
}

Witam :). To jest mój pierwszy post także przepraszam za wszystkie błędy :). Jestem początkującym adeptem C++ i nie rozumiem pewnej rzeczy. Zaimplementowałem dwie klasy, w której jedna przyjmuje liczbę (mowa o konstruktorze) i na jej podstawie definiuję tablicę. Druga natomiast posiada statyczną tablicę i poprzez moją własną metodę ma doklejać do niej elementy z tablicy z poprzedniej klasy. 

Z mojej wiedzy wynika, że jak się posiada zmienne wskaźnikowe w klasie oraz stosuję się ich dynamiczną alokację to w destruktorze powinno się zwalniać pamięć tak więc zrobiłem. Niestety mój program wyświetla jakieś wartości śmieciowe. Co ciekawe kiedy usunę destruktor z klasy A to program działa poprawnie. 

Zastanawia mnie jeden fakt czy to ma prawo bytu i jest prawidłowe bez destruktora. Powołując się na prawo przydzieliłeś pamięć operatorem new to go zwolnij delete :). Pewnie czegoś nie widzę i nie rozumiem. Wskaźniki niestety nie są moją mocną stroną :)

1 odpowiedź

+1 głos
odpowiedź 30 marca 2020 przez tangarr Mędrzec (154,780 p.)
wybrane 30 marca 2020 przez Quegon23
 
Najlepsza

Zmienna statyczna klasy istnieje poza klasą. Tak na prawdę jest to zmienna globalna, która istnieje nawet wtedy, gdy nie ma żadnej instancji tej klasy.

Zwalnianie pamięci przydzielonej do zmiennej statycznej klasy w jej destruktorze jest złym pomysłem. Natomiast zwalnianie tej pamięci i niezerowanie wskaźnika jest BARDZO złym pomysłem.
Do zwolnienia takiej pamięci proponowałbym utworzenie osobnej statycznej funkcji, którą możesz wywołać przed wyjściem z programu.

class B
{
    private:
        static char* vars;
        static int size_vars;
 
    public:
        static void show()
        {
            // zakończ funkcję jeżeli nie ustawiono zmiennej vars 
            if (vars == nullptr)
                return;
            for(int i=0; i<size_vars; i++)
                cout << vars[i] << " : ";
        }
        void change(char* v, int n)
        {
            // dodaj 1 bajt dla znaku nowej linii
            char* new_var = new char[size_vars + n + 1];
            
            // zawartość starej tablicy kopiujemy tylko wtedy gdy istnieje
            if (vars != nullptr) {
                for(int i=0; i<size_vars; i++)
                    new_var[i] = vars[i];
                // stara tablica nie jest już potrzebna
                delete[] vars;
            } 
            for(int i=size_vars; i<size_vars+n; i++)
                new_var[i] = v[i-size_vars];
            vars = new_var;
            size_vars += n;
            
            // dodajemy znak końca linii
            vars[size_vars] = 0;
        }
        static void destroy() {
            delete [] vars;
            vars = nullptr;
            size_vars = 0;
        }
};

Ponadto zauważyłem, że podczas inicjalizacji zmiennej B::var używasz nieprawidłowego wskaźnika.
Instrukcja A(0,3).getvar() tworzy instancję klasy A i zwraca wskaźnik żyjący w tym obiekcie.
Niestety ta instancja klasy A jest niszczona w następnej linii. Wywoływane jest destruktor klasy A. Pamięć jest zwalniana. Zmienna B::var wskazuje na zwolnioną pamięć.

Aby rozwiązać ten problem przypisz do zmiennej B::var nullptr lub zaalokuj nowy napis (w obu przypadkach ustaw prawidłową wartość zmiennej B::size_vars)

 

char* B::vars = new char[4]{'X','Y','Z', 0};
int B::size_vars = 3;


// lub 
// char* B::vars = nullptr;
// int B::size_vars = 0;

 

komentarz 30 marca 2020 przez Quegon23 Nowicjusz (150 p.)

Witaj Tangarr  :)

Rozumiem, że przegapiłem ten moment, gdzie zmienna B::vars wskazuje na zwolniono pamięć i właśnie dlatego program mi działał pseudo poprawnie bez destruktora. Pseudo poprawnie oczywiście, dlatego że jeszcze miałem masę błędów, gdzie przy większym rozrastaniu programu mógłby zacząć się sypać tak czy siak. Bardzo Ci dziękuje za wszystkie podpowiedzi i propozycje do mojego kodu i za czas i chęci podjęcia rozwiązania mojego problemu. 

1
komentarz 30 marca 2020 przez j23 Mędrzec (194,920 p.)

Zrób B::vars typu static std::vector i problem usuwania pamięci zniknie.

Podobne pytania

0 głosów
1 odpowiedź 410 wizyt
pytanie zadane 27 września 2020 w C i C++ przez sebaaas Początkujący (350 p.)
0 głosów
2 odpowiedzi 239 wizyt
pytanie zadane 9 lutego 2019 w C i C++ przez jankustosz1 Nałogowiec (35,880 p.)
0 głosów
2 odpowiedzi 424 wizyt
pytanie zadane 21 lutego 2018 w C i C++ przez Mihost Nowicjusz (240 p.)

92,539 zapytań

141,382 odpowiedzi

319,477 komentarzy

61,928 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...