Dynamiczna alokacja pamieci w c++ i obsluga błędów try i catch(bad_alloc))

1

Chciałbym zapytać czy zastosowana w tej grze obsluga wyjatkow ma sens tzn. czy sa w tym bledy oraz jak ewentualnie napisac to lepiej ?

By nie zasmiecac podaje zrodlo calego programu :
http://pastebin.com/tdNhYG7y

a to miejsce o ktore pytam:

 
GRACZ* stworz_gracza(int nr)//przy imieniu gracz jest przelenienei bufora
{
    system("cls");
    int i;
    int blad = 0;
    unsigned int znak;
    char nick[31];
    cout<<"\n\nPodaj imie gracza "<<nr<<" (max 30 znakow)\n\n";
    for(i = znak = 0;;++i)
    {
        znak = getchar();
        if(i < 30 && znak != '\n')
            nick[i] = znak;
        if(i > 0 && znak == '\n')
            break;
    }
    nick[i]='\0';
    try
    {
        GRACZ* player = new GRACZ [sizeof(GRACZ)];
        try
        {
            player->nazwa = new char [sizeof(nick)];
            strncpy(player->nazwa, nick, sizeof(char[31]));
            try
            {
                player->h_pry = new char [sizeof(char[41])];
                try
                {
                    player->h_pub = new char [sizeof(char[41])];
                    player->punkty = 0;
                    return player;
                }
                catch(bad_alloc)
                {
                    blad = 4;
                    delete [] player->h_pry;
                    delete [] player->nazwa;
                    delete [] player;
                }
            }
            catch(bad_alloc)
            {
                blad = 3;
                delete [] player->nazwa;
                delete [] player;
            }
        }
        catch(bad_alloc)
        {
            blad = 2;
            delete [] player;
        }
    }
    catch(bad_alloc)
    {
        blad = 1;
    }
    if(blad > 0)
    {
        system("cls");
        cout<<"Blad alokacji pamieci numer na etapie: "<<blad<<" \n\n\tZa chwile powrocisz do menu.\n\n\n Prosze ponow probe gry\n\n";
        Sleep(10000);
        system("cls");
        return 0;
    }
}
0

Wystarczy ci jeden try i jeden catch. Albo wcale, bo przy takich małych alokacjach new może wysypać wyjątkiem tylko przy bardzo skrajnych okolicznościach, przy których prędzej i tak zobaczyłbyś bluescreena.
A okoliczności i tak się już nie powtórzą, więc co za różnica w której linijce był błąd alokacji.

Daj sobie po prostu spokój z bad_alloc, chyba że alokujesz jakieś gigabajty.

  GRACZ* player = new GRACZ [sizeof(GRACZ)];

Alokujesz tablicę graczy o tylu elementach, ile bajtów zajmuje jeden gracz. Chyba nie o to chodziło.

  player->nazwa = new char [sizeof(nick)];

Dlaczego to jest tutaj, a nie w konstruktorze gracza?

  strncpy(player->nazwa, nick, sizeof(char[31]));

Użyj typu string.

player->h_pry = new char [sizeof(char[41])];

To ci przypadkowo działa dobrze, ale powinno chyba być

player->h_pry = new char[41];

a poza tym użyj typu string.

0

Bez sensu. Jakie to ma dla kogokolwiek znaczenie gdzie poleciał bad alloc? o_O Użytkownika to już szczególnie nie interesuje. Ważne że poleciał i dlatego program się położył. Zostawiłbym więc tylko to najbardziej zewnętrzne try..catch
Poza tym jesli poleciał wyjątek to raczej nic się nie zaalokowało i nie powinieneś nic zwalniać bo program się całkiem wysypie. Proponuje nullować te wskaźniki i robić delete tylko jeśli nie są nullami.

0

Azarien dzięki faktycznie to całą tablice alokowało ;)
Shalom zgadzam się, że tyle tego nie potrzeba, ale teoretycznie te delete'y są chyba ok, znaczy wydaje mi się, że nie kasują niczego niewłąściwego w razie wystąpienia wyjątku ? Jeżeli się mylę to mnie popraw

0

Mylisz się. Jeśli nic się nie zaalokowało to te wskaźniki pokazują w jakieś dziwne miejsce w pamięci i delete na nich może ci położyć program.

Notice that an invalid value of ptr causes undefined behavior.

źródło: http://www.cplusplus.com/reference/new/operator%20delete/

0

Beztytuup_neseaqs.png

Na czerwono zaznaczyłem jak leci program gdy alles jest ok.
pozozstałe kolory pokazuja jak cos na jakims etapie sie nie powiedzie.
Np lecimy kolorem jasno niebieskim i mamy:

  1. zaalokowany player
    2)zaalokowana player-> nazwa
    3)kopiowanie strncpy() do nazwy
  2. WYJATEK przy probie alokowania player->h_pry

5)blad = 3
6)kasujemy nazwe, ktora przeciez juz ybla alokowana poprawnie
7) to samo player byl alokowany
8) cala funkcja zwrac do maina 0
Tak to widze, gdzie się mylę ?

zmniejszenie rozmiaru obrazu i dodanie go do załączników posta - fp

0

Jasne, rozumiem, a mógłbyś zaproponować w jaki sposób przy pomocy jednego catch'a kasowac bezpiecznie tak by nie zostawaly smieci ? Dopiero się tego ucze i nie wiem jak to rozwiązać

0

w jaki sposób przy pomocy jednego catch'a kasowac bezpiecznie tak by nie zostawaly smieci ?

  1. pilnujesz by wskaźniki przed alokacją były NULL (a nie niezdefiniowane)
  2. w catch robisz delete[] na wszystkim, bez sprawdzania. delete na NULLu jest bezpieczne, nic się nie stanie.
0

Użyj RAII! Alokacja pamięci na składowe obiektu danej klasy powinna następować w konstruktorze (jakiejś metodzie inicjującej) i powinna być zwalniana w destruktorze. Tym sposobem pozbędziesz się miliarda try/catch + konieczności pamiętania o zwolnieniu pamięci.

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