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

Destruktor

Ostatnio zmodyfikowano 2009-09-24 18:08
Autor Wiadomość
steckel
Temat założony przez niniejszego użytkownika
Destruktor
» 2009-09-24 16:57:54
Program wysypuje się, a debugger wskazuje na destruktor:
C/C++
class statek {
private:
    int dlugosc;
    bool * uszkodzenie;
public:
    statek();
    ~statek();
};

class gracz {
private:
    statek statki[ ILOSC_STATKOW ];
public:
    gracz();
};
gracz::gracz() {
    for( int a = 0; a < 10; a++ ) {
        switch( a ) {
        case 0:
        case 1:
        case 2:
        case 3:
            statki[ a ] = statek( 0, 0, 1, true );
            break;
        case 4:
        case 5:
        case 6:
            statki[ a ] = statek( 0, 0, 2, true );
            break;
        case 7:
        case 8:
            statki[ a ] = statek( 0, 0, 3, true );
            break;
        case 9:
            statki[ a ] = statek( 0, 0, 4, true );
        }
    }
}



statek::statek( int x, int y, int dl, bool poz ) {
    dlugosc = dl;
    uszkodzenie = new bool[ dlugosc ];
    for( int a = 0; a < dl; a++ ) {
        uszkodzenie[ a ] = false;
    }
}
statek::~statek() {
    delete uszkodzenie;
}

statek::statek() {
    dlugosc = 1;
    uszkodzenie = new bool[ dlugosc ];
    for( int a = 0; a < dlugosc; a++ ) {
        uszkodzenie[ a ] = false;
    }
}
Większość kodu usunąłem, bo nie sądzę, aby był istotny.
P-10413
pompom
» 2009-09-24 17:46:38

statki[a]=statek(0,0,1,true);
1. tworzysz obiekt tymczasowy statek na stosie.
2. następnie konstruktor kopiujący obiektu statek[a] kopiuje całą zawartość obiektu tymczasowego - wartość zmiennej uszkodzenie (adres buforu) i zmienną dlugosc.
2 alternatywny. Konstruktor kopiujący jest wywoływany dwa razy - raz dla przekazania argumentu do konstruktora kopiującego statek[a], a potem w samym statek[a]. W takiej sytuacji delete w destruktorze argumentu konstruktora kopiującego statek[a] w argumencie dostanie adres już zwolnionego buforu. W normalnej sytuacji nic się nie stanie (delete nie powoduje wyjątków), ale wersja do debugowania pod debugerem specjalnie łapie takie rzeczy. Stąd błąd w destruktorze.

Zapewne w wersji skompilowanej w wersji debug zachodzi druga sytuacja, w wersji release pierwsza (kompilator optymalizuje i konstruktor kopiujący jest wywoływany tylko raz).

3. obiekt tymczasowy jest niszczony, a pamięć zaalokowana jest dealokowana*.
4. w którymś miejscu, odwołujesz się do zmiennej uszkodzenie w statek[x]. Jest to adres zdealokowanego bufora - nic tam nie ma. Występuje błąd.

Rozwiązania (od najlepszego do najgorszego):
1. Zamień bool *uszkodzenie na vector<bool> uszkodzenie.
2. nadpisz konstruktor kopiujący tak, żeby kopiował zawartość buforu, a nie tylko adres.
3. użyj boost::shared_array, zlicza on referencje, zwolni obiekt kiedy w całym programie nie będzie do niego referencji.
4. zabroń kopiowania (prywatny konstruktor kopiujący) i stwórz metodę initialize (konstruktor w miejscu).

* powinieneś użyć delete [], a nie delete. Ale dla typów prostych efekt jest taki sam.

P.S. Do wypełniania pamięci użyj std::fill zamiast pętli.
fill(uszkodzenie, &uszkodzenie[dlugosc], 0);
Czytelniej i krócej.
P-10414
steckel
Temat założony przez niniejszego użytkownika
» 2009-09-24 18:08:23
Nie wiem czy mi się to opłaci, ale poszedłem na łatwiznę i napisałem
bool uszkodzenie[ 4 ];
 i odpowiednio pozmieniałem resztę kodu. Teraz nie mam problemów. Dzięki za wyjaśnienie.
P-10415
« 1 »
  Strona 1 z 1