Konstruktor, destruktor

0

Chciałbym zrozumieć dlaczego taki kod jak zamieściłem niżej dwukrotnie usuwa obiekt.
Dlaczego po delete program jest w stanie wypisać pole obiektu, a po PAUSE usuwa jeszcze raz obiekt.
(Problem mam w większym nieco programie, ale żeby nie wrzucać tu 400 linijek, wyjąłem tylko to, co jest istotne).

Mógłby mi ktoś wyjaśnić jak działa w końcu ten destruktor?

#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;

class mojaKlasa
{
    public:
        int pole;
        mojaKlasa()
        {
            pole = 100;
        }
        mojaKlasa(int x)
        {
            pole = x;
        }
        
        ~mojaKlasa()
        {
            cout << "Usuwanie obiektu! Komunikat destruktora, tylko w celach naukowych\n";
        }
};
int main(int argc, char *argv[])
{
    mojaKlasa obiekt(23);
    cout << "obiekt.pole = " << obiekt.pole << endl;
    delete(&obiekt);
    cout << "obiekt.pole = " << obiekt.pole << endl;
    system("PAUSE");
    return 0;
}
        
 
2

Tworzysz obiekt na stosie, więc dealokacja tego obszaru nastąpi automatycznie po opuszczeniu zakresu funckji.

1

Okej, więc dlaczego nie mogę usunąć własnoręcznie obiektu? Niby program się kompiluje, ale przy włączeniu wywala błąd
Tworzę dwa obiekty i chcę jeden usunąć, a drugi zostawić. Czemu po zakomentowaniu delete jest ok, a z delete jest źle?

 #include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;

class mojaKlasa
{
    public:
        int pole;
        mojaKlasa()
        {
            pole = 100;
        }
        mojaKlasa(int x)
        {
            pole = x;
        }
        
        ~mojaKlasa()
        {
            cout << "Usuwanie obiektu! Komunikat destruktora, tylko w celach naukowych\n";
        }
};
int main(int argc, char *argv[])
{
    mojaKlasa obiekt(23);
    mojaKlasa obiekt2;
    cout << "obiekt.pole = " << obiekt.pole << endl;
    cout << "obiekt2.pole = " << obiekt2.pole << endl;
    delete(&obiekt);
    cout << "obiekt2.pole = " << obiekt2.pole << endl;
    system("PAUSE");
    return 0;
}
4

Przecież otrzymałeś już odpowiedź.
delete służy tylko i wyłącznie do zwalniania pamięci obiektów które zostały wcześniej utworzone przy użyciu new.

0

Okej, dziękuję. W sumie nie widzę, gdzie taka odpowiedź jest, ale nieważne.
To mam jeszcze jedno pytanie: jak usunąć (zwolnić pamięć) obiekt utworzony tak jak wyżej?

0

Satirev:
Tworzysz obiekt na stosie, więc dealokacja tego obszaru nastąpi automatycznie po opuszczeniu zakresu funckji.

4
    mojaKlasa *wob=new mojaKlasa(123);
    if(true)
      {
       mojaKlasa ob(456);
       cout << "ob.pole = " << ob.pole << endl;
      } // tu nastąpi automatyczna dealokacja i automatyczne wywołanie destruktora
    cout << "wob->pole = " << wob->pole << endl;
    cout << "(*wob).pole = " << (*wob).pole << endl;
    cout << "wob[0].pole = " << wob[0].pole << endl;
    delete wob; // wob - ręcznie przydzielono więc ręcznie trzeba zrobić dealokację - destruktor - nadal automatyczne
0

Tak! Dziękuję Wam :) Rozumiem już teraz

0

Mam jeszcze jedno pytanie. Dlaczego pola zajete są puste?

 #include<cstdio>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<cstring>
#include<sstream>
#include<vector>
     
using namespace std;
class blad
{
    public:
    double max, zajete, roznica;
    blad()
    {
        cerr << "blad !\n";
    }
    blad(double m, double z, double r)
    {
        max = m;
        zajete = z;
        roznica = r;
    }
};
class blad2
{
    public:
    double roznica;
    string tekst;
    blad2(double r)
    {
        roznica = r;
        tekst = "Blad !\n";
    }
};
class pojemnik
{
    public:
    double max, zajete;
    pojemnik()
    {
        max = 3.14;
        zajete = 0;
    }
    pojemnik(double d2, double d3)
    {
        max = d2;
        zajete = d3;
    }
    
    pojemnik( const pojemnik &old)
    {
        max = old.max;
        zajete = 0;
    }
    double dodaj(double);
};
double pojemnik::dodaj(double ile)
{
    double roznica = 0;
    zajete += ile;
    if(zajete > max)
    {
        roznica = zajete - max;
        zajete = max;
        throw(blad(max, zajete, roznica));
    }
    return roznica;
}
class multipojemnik
{
    public:
    string nazwa;
    int multi_max;
    vector <pojemnik> tablica;
    multipojemnik()
    {
        nazwa = "MULTIpojemnik!";
        multi_max = 10;
    }
    multipojemnik(string naz, int m)
    {
        nazwa = naz;
        multi_max = m;
    }
    void dolej(double);
};
void multipojemnik::dolej(double ile)
{
    if(ile > 0)
    {
        if(tablica.size() == 0)
        {
            cout << "\tmsg: wektor jest pusty tablica.size() == 0\n\tmsg: tworze obiekt i wrzucam go do wektora\n";
            pojemnik a = pojemnik(15, 0);
            cout << "\tmsg: tworze obiekt; jego pole max=" << a.max << " jego pole zajete=" << a.zajete << endl;
            tablica.push_back(a);
            cout << "\tmsg: dodaje do pierwszego elementu tablicy wartosc " << ile << endl;
            try
            {
                (tablica.back()).dodaj(ile);
            }
            catch(blad e)
            {
                dolej(e.roznica);
            }
        }
        else if( (tablica.size() > 0) && (tablica.size() < multi_max))
        {
            cout << "\tmsg: wektor ma " << tablica.size() << " pozycji\n";
            if( (tablica.back()).zajete < (tablica.back()).max )
            {
                cout << "\tmsg: pole zajete jest mniejsze od max (w ostatnim elemencie jest miejsce); probuje dodac do ostatniej pozycji wektora " << ile << endl;
                try
                {
                    (tablica.back()).dodaj(ile);
                }
                catch (blad e)
                {
                    dolej(e.roznica);
                }
            }
            else
            {
                cout << "\tmsg: ostatnia pozycja w tablicy jest pelna;\n";
                pojemnik b = pojemnik(tablica.back());
                cout << "\tmsg: tworze obiekt; jego pole max=" << b.max << " jego pole zajete=" << b.zajete << endl;
                cout << "\tmsg: i wrzucam do tablicy na ostatnia pozycje\n";
                tablica.push_back(b);
                cout << "\tmsg: dodaje do nowego obiektu " << ile << endl;
                try
                {
                    (tablica.back()).dodaj(ile);
                }
                catch (blad e)
                {
                    dolej(e.roznica);
                }
            }
        }
        else
        {
            blad2 f = blad2(ile);
            throw(f);
        }
    }
}
int main(int argc, char *argv[])
{
    double razem = 0;
    multipojemnik pierwszy;
    try
    {
        pierwszy.dolej(234);
    }
    catch(blad2 f)
    {
        cout << f.tekst << "Do dodalania pozostalo: " << f.roznica << endl;
    }
    cout << "\n==========STAN==========\n\n";
    cout << "NR\tZAJETE\tMAX\n";
    for(int i=0; i<pierwszy.tablica.size(); i++)
    {
        cout <<"#" << i+1 << "\t" << pierwszy.tablica[i].zajete << "\t" << pierwszy.tablica[i].max << endl;
        razem +=pierwszy.tablica[i].zajete;
    }
    cout << "RAZEM:\t" << razem << endl;
    if(pierwszy.tablica.size()==0)
    cout << "_____brak pojemnikow____\n";
   
    
    system("PAUSE");
    return 0;
}
0

Zerujesz pole w konstruktorze kopiującym, a ten wykorzystywany jest podczas realokacji wektora, i jego przewidywanym działaniem jest stworzenie dokładnej kopii.
Postaraj się oddzielić we/wy od części algorytmicznej, bardzo utrudnia to analizę.
Przekombinowałeś. Rekurencja + wyjątki? Ewidentnie coś tu robisz na siłę.

0
Flaker napisał(a):

Zerujesz pole w konstruktorze kopiującym, a ten wykorzystywany jest podczas realokacji wektora, i jego przewidywanym działaniem jest stworzenie dokładnej kopii.

Nie do końca rozumiem...
Zeruję, bo chcę by nowy obiekt był identyczny jak wcześniejszy, ale żeby jego pole zajete było równe 0.

Flaker napisał(a):

Postaraj się oddzielić we/wy od części algorytmicznej, bardzo utrudnia to analizę.

Tego też nie rozumiem

Flaker napisał(a):

Przekombinowałeś. Rekurencja + wyjątki? Ewidentnie coś tu robisz na siłę.

A jak inaczej mógłbym to zrobić? Rzucam wyjątkiem, kiedy jeden obiekt jest "pełny" by przekazać zmienna ile do wywołania ponownie...

EDIT:
okej, zrobiłem w pętli bez rekurencji... Rozwiązuje problem przekombinowania, nie rozwiązuje problemu kontruktora kopiujacego...

0

Prościej będzie "jechać" pętlą po wektorze i wypełniać/dopełniać kolejne pojemniki.

Apropos realokacji: wektor działa w taki a nie inny sposób, że czasami musi skopiować obiekty w inne miejsce pamięci, i wtedy korzysta z ww. konstruktora. A Twój nie robi kopii tylko bliżej nieokreślone coś, przez co po pewnym czasie masz w wektorze nie to co do niego wkładałeś.

Apropos utrudniania analizy: mieszanie co chwila wypisywanych rzeczy na ekran z tym, co tak na prawdę sprawia że program działa pogarsza czytelność. Może wybrzydzam, ale to się trudno czyta.

0

Znalazłem błąd... To znaczy w metodzie pojemnik::dodaj
Lepiej zrobić tak:

double pojemnik::dodaj(double ile)
{
    double roznica = 0;
    zajete += ile;
    if(zajete > max)
    {
        roznica = zajete - max;
        zajete = max;
    }
    throw(blad(max,zajete,roznica));
    return roznica;
}

niż

 if(zajete > max)
    {
        roznica = zajete - max;
        zajete = max;
        throw(blad(max,zajete,roznica));
    }
Flaker napisał(a):

Prościej będzie "jechać" pętlą po wektorze i wypełniać/dopełniać kolejne pojemniki.

Hmmm... może masz rację. Ale zrobiłem tak:

void multipojemnik::dolej(double ile)
{
    while(ile!=0.0)
    {
        cout << "ILE = " << ile << endl;
        if(ile > 0)
        {
            if(tablica.size() == 0)
            {
                cout << "\tmsg: wektor jest pusty tablica.size() == 0\n\tmsg: tworze obiekt i wrzucam go do wektora\n";
                pojemnik a = pojemnik(15, 0);
                cout << "\tmsg: tworze obiekt; jego pole max=" << a.max << " jego pole zajete=" << a.zajete << endl;
                tablica.push_back(a);
                cout << "\tmsg: dodaje do pierwszego elementu tablicy wartosc " << ile << endl;
                try
                {
                    (tablica.back()).dodaj(ile);
                }
                catch(blad e)
                {
                    ile = e.roznica;
                }
            }
            else if( (tablica.size() > 0) && (tablica.size() < multi_max))
            {
                cout << "\tmsg: wektor ma " << tablica.size() << " pozycji\n";
                if( (tablica.back()).zajete < (tablica.back()).max )
                {
                    cout << "\tmsg: pole zajete jest mniejsze od max (w ostatnim elemencie jest miejsce); probuje dodac do ostatniej pozycji wektora " << ile << endl;
                    try
                    {
                        (tablica.back()).dodaj(ile);
                    }
                    catch (blad e)
                    {
                        ile = e.roznica;
                    }
                }
                else
                {
                    cout << "\tmsg: ostatnia pozycja w tablicy jest pelna;\n";
                    pojemnik b = pojemnik(tablica.back());
                    cout << "\tmsg: tworze obiekt; jego pole max=" << b.max << " jego pole zajete=" << b.zajete << endl;
                    cout << "\tmsg: i wrzucam do tablicy na ostatnia pozycje\n";
                    tablica.push_back(b);
                    cout << "\tmsg: dodaje do nowego obiektu " << ile << endl;
                    try
                    {
                        (tablica.back()).dodaj(ile);
                    }
                    catch (blad e)
                    {
                        ile = e.roznica;
                    }
                }
            }
            else
            {
                blad2 f = blad2(ile);
                throw(f);
            }
        }
    }
}
Flaker napisał(a):

Apropos realokacji: wektor działa w taki a nie inny sposób, że czasami musi skopiować obiekty w inne miejsce pamięci, i wtedy korzysta z ww. konstruktora. A Twój nie robi kopii tylko bliżej nieokreślone coś, przez co po pewnym czasie masz w wektorze nie to co do niego wkładałeś.

Rozumiem.. W takim razie, jak zrobić obiekt z polem zajete równym 0 na bazie ostatniego elementu w wektorze?

Flaker napisał(a):

Apropos utrudniania analizy: mieszanie co chwila wypisywanych rzeczy na ekran z tym, co tak na prawdę sprawia że program działa pogarsza czytelność. Może wybrzydzam, ale to się trudno czyta.

Oczywiście masz rację. Generalnie do klas i metod nie wrzucam wypisywania żadnego. Tutaj zrobiłem wyjątek tylko ze względu na grzebanie w kodzie i chęć dowiedzenia się, jak to leci i gdzie się wysypuje.

1

Twój "lepszy" pojemnik::dodaj jest absurdalny. Dlaczego niby ta funkcja ma zawsze i niezależnie od stanu pojemnika i argumentu rzucać wyjątkiem?
Po wprowadzeniu tej modyfikacji program działa, jednak jego działanie nie jest specjalnie logiczne.

Sugestią z pętlą chciałem zwrócić uwagę że da się program napisać zdecydowanie prościej, tj bez wyjątków i rekurencji, ale chodziło też o zupełnie inne podejście do problemu i napisanie funkcji z innego punktu widzenia.

Ot, chociażby coś takiego:

void multipojemnik::dolej(double ile)
{
	if(ile<0.) throw "Argument ujemny.";
	double ddod;
	
	for(int i=0; i < tablica.size();i++)
	{
		ddod = tablica[i].max-tablica[i].zajete;
		ddod=std::min(ddod,ile);
		tablica[i].dodaj(ddod);
		ile-=ddod;
		if(ile==0.) return;
	}
	
	while(ile>0)
	{
		if(tablica.size()>=multi_max) 
			throw ile;
		
		ddod = std::min(15.,ile);
		pojemnik p = pojemnik(15.,ddod);
		tablica.push_back(p);
		ile-=ddod;
	}
}

Kod oczywiście pod starą wersję pojemnik::dodaj.

0
Flaker napisał(a):

Twój "lepszy" pojemnik::dodaj jest absurdalny. Dlaczego niby ta funkcja ma zawsze i niezależnie od stanu pojemnika i argumentu rzucać wyjątkiem?
Po wprowadzeniu tej modyfikacji program działa, jednak jego działanie nie jest specjalnie logiczne.

Racja.. Wyjątki muszą być. To poprawię. Ale co z tym konstruktorem kopiującym?

1

Jak już wcześniej pisałem, jego celem jest utworzenie obiektu identycznego do tego przekazanego jako argument. Takie założenia przyjmuje wektor, i inne kontenery biblioteki standardowej. W Twoim przypadku nie ma potrzeby tworzenia go (kompilator automatycznie tworzy odpowiedni).
Jeśli chcesz otrzymać nowy obiekt o pojemności starego, ale niewypełniony, to lepiej będzie albo utworzyć funkcję zwracającą pustą kopię, albo konstruktorem: pojemnik nowy = pojemnik(stary.max,0.).

0

Dziękuję Ci bardzo :)

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