Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Crash w momencie działania destruktora.

Ostatnio zmodyfikowano 2014-12-17 19:11
Autor Wiadomość
owocowy
Temat założony przez niniejszego użytkownika
[C++] Crash w momencie działania destruktora.
» 2014-12-15 22:39:26
Witam !

Chciałem pobawić się trochę klasami i dynamiczną alokacją pamięci, więc napisałem jakiś tam prosty programik. Jego treść nie ma absolutnie znaczenia, gdyż rozchodzi się jedynie o destruktor. W skrócie wygląda to tak:

W programie są 3 klasy:

KlasaA - posiada tylko 2 składniki typu int.

KlasaB - posiada wskaźnik do obiektów klasy KlasaA ( KlasaA *tablicaA; ). W konstruktorze inicjalizuje ten wskaźnik adresem zwróconym przez operator new. ( tablicaA = new KlasaA[1]; ).
W destruktorze KlasyB, pozbywam się zaalokowanej pamięci ( delete[] tablicaA; )

KlasaC - posiada wskaźnik do obiektów klasy KlasaB ( KlasaB *tablicaB; ). W konstruktorze inicjalizuje ten wskaźnik adresem zwróconym przez operator new. ( tablicaB = new KlasaB[1]; ).
W destruktorze KlasyC, pozbywam się zaalokowanej pamięci ( delete[] tablicaB; )

W funkcji main tworzę obiekt klasyC ( KlasaC obiekt; ) . Przy końcu aplikacji, program "wysypuje się". Dostaje komunikat o błędzie w destruktorze KlasyB. Udało mi się to jakoś naprawić usuwając destruktor z klasyB, a w destruktorze KlasyC dopisuję... ( delete[] tablicaB->tablicaA; delete[] tablicaB; )

Jestem ciekaw dlaczego tak się dzieję, dlaczego w klasieB nie mogę mieć destruktora, który zwalnia wcześniej zaalokowaną pamięć. Jedyne co przychodzi mi do głowy to, że wcześniej najpierw uruchamiał się destruktor klasyC i w momencie zwalniania pamięci, pozbywał się też tej zaalokowanej przez wskaźnik z KlasyB, a że klasaB też posiadała destruktor, to po raz drugi usuwała to co znajduje się pod wskaźnikiem tablicaA.
P-122920
Monika90
» 2014-12-16 08:15:18
Nie wiadomo dlaczego tak się dzieje, ponieważ nie pokazałeś kodu. Prawdopodobnie nie zdefiniowałeś konstruktora kopiująceo i operatora przypisania w klasach B i C.
P-122930
owocowy
Temat założony przez niniejszego użytkownika
» 2014-12-16 16:02:32
Udało mi się znaleźć błąd, polegał on właśnie na błędnym przypisaniu. Jednak wrzucę cały kod, żeby dowiedzieć się co robię źle, bo mam dziwne wrażenie, że niektóre rozwiązania mimo, że działają to są błędne i czy przypadkiem nie ma wycieków pamięci.

KlasaA - Karta
C/C++
class karta {
private:
    int a, b;
public:
    karta( int aa = 0, int bb = 0 )
        : a( aa )
         , b( bb )
    { };
    friend class talia;
};

KlasaB - Talia
C/C++
class talia {
private:
    int rozm;
    string nazwa;
    karta * tab;
public:
    talia( string name = "nowa talia" )
        : rozm( 1 )
         , nazwa( name )
    { tab = new karta[ 1 ]; };
    ~talia();
    karta * dodaj();
    void wyswielt();
    friend class gra;
};

C/C++
karta * talia::dodaj()
{
    int ile;
    karta * tab2;
    cout << "Ile kart: ";
    cin >> ile;
    tab2 = new karta[ rozm + ile ];
   
    for( int i = 0; i < rozm; i++ )
    {
        tab2[ i ] = tab[ i ];
    }
   
    delete[] tab;
    rozm += ile;
    return tab2;
}

C/C++
void talia::wyswielt()
{
    for( int i = 0; i < rozm; i++ )
    {
        cout << tab[ i ].a << "." << tab[ i ].b << endl;
    }
}

C/C++
talia::~talia()
{
    delete[] tab;
}

KlasaC - gra
C/C++
class gra {
    talia * tab;
    int rozm;
    talia * dodaj();
    void wyswietl();
public:
    gra()
        : rozm( 1 )
    { tab = new talia[ 1 ]; };
    ~gra();
    void start();
};

C/C++
talia * gra::dodaj()
{
    talia * tab2;
    tab2 = new talia[ rozm + 1 ];
   
    for( int i = 0; i < rozm; i++ )
    {
        tab2[ i ].tab[ i ] = tab[ i ].tab[ i ];
    }
    rozm++;
    delete[] tab;
    return tab2;
}

C/C++
void gra::wyswietl()
{
    for( int i = 0; i < rozm; i++ )
    {
        cout << "Talia " << i << ": " << tab[ i ].nazwa << endl;
    }
}

C/C++
void gra::start()
{
    int wybor;
    bool petla = true;
   
    cout << "-----------MENU-----------" << endl;
    cout << "1. Stworz talie." << endl;
    cout << "2. Pokaz talie." << endl;
    cout << "3. Koniec." << endl;
   
    while( petla )
    {
        cout << endl << "Wybor: ";
        cin >> wybor;
       
        switch( wybor )
        {
        case 1:
            {
                tab = dodaj();
                break;
            }
        case 2:
            {
                wyswietl();
                break;
            }
        case 3:
            {
                petla = false; break;
            }
            default: { }
        }
    }
}

Funkcja main:
C/C++
int main()
{
    gra gra1;
    gra1.start();
}
P-122943
Monika90
» 2014-12-17 12:41:12
W przypadku klas zarządzających zasobami trzeba albo zdefiniować konstruktory kopiujące i operatory przypisania (co jest nietrywialne), albo w ogóle uniemożliwić kopiowanie, ponieważ utworzone automatycznie przez kompilator operacje będą błędne.

Ale najwazniejsze jest, że klasy reprezentujące pojęcia z dziedziny zastosowań, takie jak talia czy gra, nie powinny w ogóle zajmować się zarządzaniem pamiecią. Zarządzanie pamięcią powinno być oddelegowane do innej klasy. Standardowa biblioteka zawiera już taką klasę, nazywa się ona std::vector, więc użyj vectora.
P-122992
owocowy
Temat założony przez niniejszego użytkownika
» 2014-12-17 19:11:33
Jeżeli chodzi o konstruktory kopiująca i operatory przypisania to zdaje sobie z tego sprawę, ale wcale nie zamierzałem, znaleźć jakiegoś większego zastosowania do tych klas i nie zamierzałem ich zbytnio rozwijać. Jedyne co chciałem poćwiczyć ( spróbować, jak to się robi ) to tworzyć obiekty dynamicznie w trakcie programu, dodawać je, usuwać i zmienić. Nie przyglądałem się dokładnie klasie std::vector, ale z tego co widzę to można on być mi wielce pomocna. Dziękuję Ci za pomoc. Myślę, że temat jest już do zamknięcia.
P-123019
« 1 »
  Strona 1 z 1