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

Dodanie destruktora powoduje, że program się wysypuje

Ostatnio zmodyfikowano 2017-02-08 19:39
Autor Wiadomość
glikoo
Temat założony przez niniejszego użytkownika
Dodanie destruktora powoduje, że program się wysypuje
» 2017-02-07 18:26:20
Witam

Mam problem z poniższym kodem. Kod się kompiluje i uruchamia dopóki nie zostanie odkomentowana część z destruktorem. Nie mogę zrozumieć co jest przyczyną. Odkomentowanie destruktora sprawia, ze program dalej się kompiluje, ale od razu po uruchomieniu wyskakuje błąd.

C/C++
#include <iostream>

using namespace std;

class kuku
{
    string * tab;
public:
    kuku()
        : tab( new string[ 2 ] ) //KONSTRUKTOR DOMYSLNY
    {
        tab[ 0 ] = "none";
        tab[ 1 ] = "none2";
    }
    kuku( const string & a, const string b )
        : tab( new string[ 2 ] ) //KONSTRUKTOR PRZYJMUJACY ARGUMENTY
    {
        tab[ 0 ] = a;
        tab[ 1 ] = b;
    }
   
    kuku( const kuku & obj )
        : tab( new string[ 2 ] ) //KONSTRUKTOR KOPIUJACY
    {
        tab[ 0 ] = obj.tab[ 0 ];
        tab[ 1 ] = obj.tab[ 1 ];
    }
   
    const string & operator []( int i ) const
    {
        if( i > 1 )
        {
            i = 1;
        }
        return tab[ i ];
    }
   
    string & operator []( int i )
    {
        if( i > 1 )
        {
            i = 1;
        }
        return tab[ i ];
    }
    /*  ~kuku()
        {
          delete [] tab;
        }
    */
};

ostream & operator <<( ostream & wyjsc, const kuku & obj )
{
    wyjsc << "Imie perwszej osoby: " << obj[ 0 ] << ", imie drugiej osoby: " << obj[ 1 ] << endl;
    return wyjsc;
   
}

int main()
{
    cout << "Hello world!" << endl;
   
    kuku o1, o2; //zostana odpalone 2 konstrukotry domysle
   
    const kuku * wsk1 = new kuku( "Ala", "Ola" ); // zostanie uruchomiony konstruktor przyjmujacy 2 argumenty string
   
    const kuku o3( * wsk1 );
   
    delete wsk1;
   
    wsk1 = 0;
    wsk1 = new kuku( o3 );
    o2 = * wsk1;
   
    cout << o1 << endl;
    cout << o2 << endl;
    cout << "*************" << endl;
   
    delete wsk1;
   
    wsk1 = 0;
    o1 = kuku( "Ewa", "Iza" );
   
    cout << o1[ 0 ] << ", " << o1[ 1 ] << endl; //odnosnik1
    o1[ 1 ] = "Jan";
    cout << o1[ 0 ] << ", " << o1[ 1 ] << endl;
   
    cout << "*************" << endl;
    cout << o1[ 2 ] << endl;
    return 0;
}
P-157445
latajacaryba
» 2017-02-07 18:58:49
C/C++
o1 = kuku( "Ewa", "Iza" );
Oto ten rodzynek ;p
Napisz operator przypisania. Operator przypisania to nie konstruktor kopiujący.
Nie wgłębiałem się w kod, ale stawiam, że wskaźnik string o1 wskazuje na jakiegoś stringa w obiekcie kuku.
Tablica dynamicznie zaalokowana w kuku jest usuwana destruktorem.
Następnie to samo ma się stać z o1, ale tam nie ma czego usuwać (brak tablicy, którą usunąłby destruktor)

Napisz więc operator przypisania i odpisz, czy coś to dało ;)
P-157446
Mister123450
» 2017-02-07 19:21:39
Błąd powoduje
const kuku * wsk1 = new kuku("Ala", "Ola");
W ten sposób tworzysz wskaźnik na wartość stałą, której nie można usunąć.
Na http://kondel.dx.am/?pid=24 masz to wystarczająco opisane, ewentualnie odsyłam do Megatutorialu xiona http://xion.org.pl/files/texts/mgt/html/1_8.html
P-157447
michal11
» 2017-02-07 20:16:45
Tak jak napisał @latajacaryba nie zdefiniowałeś operatora przypisania więc został on wygenerowany automatycznie i nie byłby to problem gdyby nie to, że w twojej klasie jest wskaźnik na dynamicznie alokowaną pamięć więc automatycznie wygenerowany operator przypisania wykonuje tzw. płytkie kopiowanie czyli kopiuje tylko adresy, po takiej operacji będziesz miał dwa obiekty które wskazują na to samo miejsce w pamięci więc kiedy pierwszy zostanie usunięty poprawnie zwolni pamięć ale już kiedy zostanie wywołany konstruktor drugiego obiektu dostaniesz błąd bo będziesz chciał zwalniać już zwolnioną pamięć. Rozwiązaniem jest wspomniane napisanie swojego operatora przypisania.

@latajacaryba Mała korekta tylko
Operator przypisania to nie konstruktor kopiujący
oczywiście masz rację z tym, że taki kod
Type obj = otherObj
 wywoła konstruktor kopiujący a nie jak by się mogło wydawać operator przypisania.

@Mister123450
nie wiem skąd wziąłeś tą informację, że const pointera nie można usuwać deletem ale to nie jest prawda. Bo w zasadzie dlaczego nie można by było takiego obiektu usunąć?
Na poparcie moich słów:
http://stackoverflow.com​/questions/755196​/deleting-a-pointer-to-const-t-const
http://stackoverflow.com​/questions/6965796​/why-delete-can-perform-on-pointers-to-const-while-free-cannot
http://stackoverflow.com​/questions/756109​/how-does-delete-deal-with-pointer-constness
P-157451
latajacaryba
» 2017-02-07 21:00:11
@Up
Tak, konstruktor kopiujący jest wywoływany w przypadku
C/C++
Typ a;
Typ b = a; // konst. kopiujacy
Ale nie w przypadku
C/C++
Typ a;
Typ b;

b = a; // operator =

Tak dla autora, żeby wiedział :D

A co do programu: Jeśli nie zdefiniujesz operatora =, to zostanie on automatycznie wygenerowany na zasadzie "składnik = składnik z przypisywanego obiektu"

C/C++
class A
{
    int a;
    const int b;
    double * ptr;
   
    A( int aa, int bb, double p )
        : ptr( new double( p ) )
    {
        a = a;
        b = bb;
    }
   
};

int main()
{
    class A obj1( 1, 2, 5.5 ), obj2( 2, 3, 0.2 );
    obj1 = obj2; // rozwiniecie ponizej
}

Jeśli nie zdefiniujesz operatora = to wyjdzie to tak:
C/C++
obj1.a = obj2.a // na razie jest wszystko ok
obj1.b = obj2.b // blad, zmienna b jest const
obj1.ptr = obj2.ptr // i tu w zasadzie nie ma bledu jako takiego, ale chodzi o to, ze ptr objektu obj2 wygenerował sobie dynamicznie (new double(p)) zmienna, z wartoscia p (w tym przypadku 0.2)
//natomiast obj1.ptr WSKAZUJE na to miejsce w pamieci (jesli wskaznikiem 'a' wskazujemy na wskaznik 'b' tego samego typu(int, float itp.), to wskazujemy na zmienna/obiekt na ktory wskazuje //wskaznik 'b'). Tak wiec wskaznikiem obj1.ptr wskazujemy na to samo miejsce w pamieci co obj2.ptr. Po usunieciu (delete) przez destruktor zmiennej na ktora wskazuje obj2.ptr nic sie nie stanie. Gorzej, gdy zechcemy usunac zmienna na ktora wskazuje obj1.ptr - czyli ta, ktora wczesniej usunelismy

Jasne, czy coś niedokładnie lub źle wytłumaczyłem?
P-157453
glikoo
Temat założony przez niniejszego użytkownika
» 2017-02-08 19:39:56
@latajacaryba Tak, wszystko jasne i program już działa. Dzięki za obrazowe wytłumaczennie :)
P-157496
« 1 »
  Strona 1 z 1