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

Destruktor uruchamiany w petli

Ostatnio zmodyfikowano 2015-01-11 21:32
Autor Wiadomość
wiktor12348
Temat założony przez niniejszego użytkownika
Destruktor uruchamiany w petli
» 2015-01-07 21:44:48
Witam

Mam nadzieje że tym razem nie obniżę poziomu forum.

Mam klasę i klasę zagnieżdżona.
C/C++
class klient {
    string imie, nazwisko;
    class DataUrodzin {
        int dzien;
        int miesiac;
        int rok;
        /** metody publiczne **/
    }
public:
    DataUrodzin * data;
    klient() {
        imie = "";
        nazwisko = "";
        data = new DataUrodzin( 0, 0, 0 );
    }
    ~klient() {
        delete data;
    }
    /** metody publiczne **/
}
Konstruktor rezerwuje pamięć na Date urodzenia i usuwa w destuktorzę. Działa normalnie gdy robię:
C/C++
klient * a = new klient;
/* ... */
delete a;
Oraz jak wyświetlam itp.

Jednak muszę w pewnym momencie przekopiować Klientów:
C/C++
klient * tmp = new klient[ n + 1 ];

for( int i = 0; i < n; i++ ) {
    tmp[ i ] = k[ i ];
}

I tutaj jest coś co mnie zadziwia. Uruchamia się destruktor klasy klient. Gdy wyświetlam zawartość klasy to tej pętli to imie i nazwisko jest ok... ale data urodzenia to syf (usunął zawartość tych komórek). Dlaczego tak się dzieje, oraz jak temu zaradzić?
P-124420
akwes
» 2015-01-07 22:03:18
Kopiujesz sam wskaźnik. Rób głęboką kopię. W tym momencie kopiujesz adres wskaźnika i masz dwa obiekty pokazujące na ten sam obiekt DataUrodzin. Usunięcie jakiegokolwiek z obiektów powoduje usunięcie DataUrodzin data, a wszystkie inne kopie wskaźnika wciąż odnoszą się do tego obszaru pamięci (który już jest zwolniony). Napisz poprawny konstruktor kopiujący (domyślny konstruktor kopiujący jest niepoprawny).
P-124422
wiktor12348
Temat założony przez niniejszego użytkownika
» 2015-01-07 22:35:43
Dziękuje za odpowiedź.

Ok rozumiem.

Teraz mam taki konstruktor kopiujący:
C/C++
klient::klient( klient & copy ) {
    imie = copy.imie;
    nazwisko = copy.nazwisko;
    data = copy.data;
}

Już nie mówiąc że najprawdopodobniej nie wykona się kopiowanie daty. On się nie wykonuje. Break Point nie zatrzymuje się na tym.
P-124424
Monika90
» 2015-01-07 23:17:25
C/C++
for( int i = 0; i < n; i++ ) {
    tmp[ i ] = k[ i ];
}
To nie używa konstruktora kopiującego, lecz operatora przypisania. Nie używaj wskaźnika jako składowej klasy, to nie będziesz musiał implementować głębokiego kopiowania.
P-124430
akwes
» 2015-01-08 10:46:56
Faktycznie, @Monika90 ma rację. Zbyt pobieżnie popatrzyłem na kod.

Jednak treść konstruktora kopiującego i tak jest zła, bo dalej nie kopiujesz obiektu tylko wskaźnik do obiektu (obiektu który chcesz skopiować).

Tak jak napisała @Monika90, albo rób głęboką kopię albo nie korzystaj ze wskaźnika.

15.3 Konstruktory - dalsze szczegóły
Artykuł opisujący (mniej więcej gdzieś po kilku pierwszych akapitach) głębokie kopiowanie za pomocą konstruktora kopiującego. Oczywiście, będziesz musiał przenieść tę wiedzę na operator przypisania, co nie powinno być dla Ciebie trudne.
P-124440
wiktor12348
Temat założony przez niniejszego użytkownika
» 2015-01-11 19:31:06
@Monika90 i @akwes, taki mam wymóg, musi być. Dziękuje za pomoc.

Teraz inaczej.
C/C++
klient & klient::operator =( klient & copy ) {
    imie = copy.imie;
    nazwisko = copy.nazwisko;
    data->copy( *( copy.data ) );
    return * this;
}
C/C++
klient::DataUrodzin & klient::DataUrodzin::copy( DataUrodzin & copy ) {
    dzien = copy.dzien;
    miesiac = copy.miesiac;
    rok = copy.rok;
    return * this;
};
Działa super. Teraz jakbym chciał w operatorze= klasy klient zmienić z data->copy(*(copy.data)) na data=copy.data to nie wykonuje się ani operator przypisania ani konstruktor kopiujący. Dodawałem jeden i drugi, stawiałem break pointy, nawet tam nie wchodził. Zasadniczo tak działa, ale mogę być spytany czemu nie używam operatora= no i sam jestem ciekawy dlaczego.
P-124680
Monika90
» 2015-01-11 21:32:42
Nie wiem po co Ci funkcja DataUrodzin::copy, przecież robi ona to samo co operator przypisania.
Zamiast
data->copy( *( copy.data ) );
wystarczy napisać
*data = *copy.data;

Poza tym parametry operacji kopiujących powinny być typu const klient&
P-124690
« 1 »
  Strona 1 z 1