Heap Corruption

0

ogólnie rzecz biorąc mam napisaną klasę
której konstruktor i destruktor wyglądają następująco:

Kopiuj
total::total()
{ 
 length=1;
 znak = new unsigned int[length]; 
 znak[0]=0;           
} 
Kopiuj
 total::~total()
{
  delete [] znak;
  znak=NULL;
}

napisałem metode która zmienia mi rozmiar tej tablicy...
gdy tego potrzebuję

Kopiuj
 void total::realokacja(int dlugosc)
{
    //zapamietuje poczatek starej tablicy
    unsigned int *tmp = &znak[0];
    //tworze nowa tablice z nowym rozmiarem
    znak = new unsigned int[dlugosc];
         
    for (int j=0; j<length; ++j)    //przepisuje stara tablice do nowej
        znak[j] = tmp[j];
    for (int j=length; j<dlugosc; ++j)    //zeruje ostatni element nowej tablicy
        znak[j] = 0;
    //usuwam stara tablice
    delete [] tmp;
    tmp=NULL;
    length=dlugosc;
}

w przeciążonych operatorach tworzę sobie zazwyczaj
zmienną mojego typu

Kopiuj
 total z //wynik

na której pracuje itp itd
a przed końcem operatora np operatora += lub *= itp
robię tak:

Kopiuj
(*this)=z;
return *this; 

problem w moim mniemaniu wygląda tak, że generuje mi błąd Heap Corruption
czyli usuwam bądź cokolwiek robię źle ze wskaźnikami...
możecie mi powiedzieć czy coś w powyżej zamieszczonych opisach jest nie poprawne ??

arasso12
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 5 lat
0
Kopiuj
 

 void total::realokacja(int dlugosc)
{
    //zapamietuje poczatek starej tablicy
    unsigned int *tmp = &znak[0];
    //tworze nowa tablice z nowym rozmiarem
    znak = new unsigned int[dlugosc];
 
    for (int j=0; j<length; ++j)    //przepisuje stara tablice do nowej
        znak[j] = tmp[j];
    for (int j=length; j<dlugosc; ++j)    //zeruje ostatni element nowej tablicy
        znak[j] = 0;
    //usuwam stara tablice
    delete [] tmp;
    tmp=NULL;
    length=dlugosc;
}

Błąd, alokujesz a nie zwalniasz...

Kopiuj
 

 void total::realokacja(int dlugosc)
{
    if( dlugosc<=length )
        return;

    unsigned int *NewTab = new unsigned int[dlugosc];
 
    for (int j=0; j<length; ++j)    
        NewTab[j] = znak[j];
    
    delete []znak;

    for (int j=length; j<dlugosc; ++j)    
        NewTab[j] = 0;


    znak=NewTab;

    length=dlugosc;
}

Musisz zaalokować miejsce w pamięci na nową większą tablicę, do niej skopiować zawartość starej. Zwolnić starą tablicę i przypisać adres nowej tablicy do wskaźnika który wskazywał na starą.


non omnis moriar i tyle :-)
edytowany 3x, ostatnio: arasso12
0

jak nie zwalniam jak

Kopiuj
 void total::realokacja(int dlugosc)
{
    //zapamietuje poczatek starej tablicy
    unsigned int *tmp = &znak[0];
    //tworze nowa tablice z nowym rozmiarem
    znak = new unsigned int[dlugosc];
         
    for (int j=0; j<length; ++j)    //przepisuje stara tablice do nowej
        znak[j] = tmp[j];
    for (int j=length; j<dlugosc; ++j)    //zeruje ostatni element nowej tablicy
        znak[j] = 0;
    //usuwam stara tablice
    delete [] tmp;
    tmp=NULL;
    length=dlugosc;
}

widzimy, że w linijce

Kopiuj
     unsigned int *tmp = &znak[0];

przypisuje adres pierwszego elementu na nowy wskaźnik i potem go usuwam w tej linijce

Kopiuj
 delete [] tmp; 

Chyba, że ja czegoś nie rozumiem...

arasso12
Chyba faktycznie zwalniasz, ale robisz to dziwnie, zobacz co będzie się działo z moją wersją metody.
0

ogólnie ta funkcja ma mi zwiększać rozmiar tablicy dynamicznej
czyli jak stworze obiekt

Kopiuj
total a 

i potem wywołam na nim

Kopiuj
 a.realokacja(4)

to zwiększy mi rozmiar tej tablicy :d
tak ?

jak testowałem to to tak działa tylko, że po pewnym czasie wywala mi ten błąd huh

arasso12
W metodzie realokacja() dodaj obsługę wyjątku, jeżeli ktoś poda wielkość tablicy < niż aktualna - to może być problem.
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:5 dni
1

Twoja wersja realokacji jest poprawna.
Prawdopodobnie masz niepoprawnie zdefiniowany operator przypisania oraz konstruktor kopiujący.
Przy realokacji tmp=0 oraz w destruktorze znak=NULL to zbędne instrukcje.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
0

To są moje operatory przypisania.

Kopiuj
 total& total::operator =(const total& t)
{
  (*this).clear();
  (*this).realokacja(t.length);
  for (int j=0; j<length; ++j)    //przepisuje tablice do nowej
        this->znak[j] = t.znak[j];
  
  return *this;
}
total& total::operator =(const int& i)
{
       total z;
       int length=0;
	   int b=i,c=i;
	   while (c) 
	   { 
		     length++; 
		     c/=10; 
	   }
       z.realokacja(length); 
       for(int j=0; j < length; j++)
	   {
               z.znak[j]=b%10;
               b=b/10;
	   }
 

(*this)=z; 
return *this;   
}
0

Poniżej są moje operatory przypisania...
szukam błędu już od nie wiem ilu dni 4 czy więcej i się doszukać nie potrafię

Kopiuj
 total& total::operator =(const total& t)
{
  (*this).clear();
  (*this).realokacja(t.length);
  for (int j=0; j<length; ++j)    //przepisuje tablice do nowej
        this->znak[j] = t.znak[j];
  
  return *this;
}
total& total::operator =(const int& i)
{
       total z;
       int length=0;
	   int b=i,c=i;
	   while (c) 
	   { 
		     length++; 
		     c/=10; 
	   }
       z.realokacja(length); 
       for(int j=0; j < length; j++)
	   {
               z.znak[j]=b%10;
               b=b/10;
	   }
 

(*this)=z; 
return *this;   
}
0
Kopiuj
 total& total::operator =(const total& t)
{
  (*this).clear();
  (*this).realokacja(t.length);
  for (int j=0; j<length; ++j)    //przepisuje tablice do nowej
        this->znak[j] = t.znak[j];
  
  return *this;
}
total& total::operator =(const int& i)
{
       total z;
       int length=0;
	   int b=i,c=i;
	   while (c) 
	   { 
		     length++; 
		     c/=10; 
	   }
       z.realokacja(length); 
       for(int j=0; j < length; j++)
	   {
               z.znak[j]=b%10;
               b=b/10;
	   }
 

(*this)=z; 
return *this;   
}
0

troche za dużo razy to wysłałem ;d przepraszam ale proszę o odpowiedź

0
shial napisał(a):
Kopiuj
total& total::operator =(const int& i)
{
       total z;
...
(*this)=z; 
return *this;   
}

Nie zwracaj wskaźnika lub referencji do obiektu lokalnego w bloku funkcji. Dodatkowo zastanów się kiedy zostanie wykonany destruktor dla total z; i co on zrobi.

0
heap napisał(a):
shial napisał(a):
Kopiuj
total& total::operator =(const int& i)
{
       total z;
...
(*this)=z; 
return *this;   
}

Nie zwracaj wskaźnika lub referencji do obiektu lokalnego w bloku funkcji. Dodatkowo zastanów się kiedy zostanie wykonany destruktor dla total z; i co on zrobi.

Sorki, nie przeczytałem dokładnie treści całego wątka. Druga część pytania jak najbardziej aktualna.

SH
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 6 lat
  • Postów:69
0
Kopiuj
 total& total::operator =(const int& i)
{
       total z;
...
(*this)=z; 
return *this;   
}

ale ja tutaj wyłuskuje obiekt ze wskaźnika i pod ten obiekt przypisuje obiekt z
i zwracam mój obiekt

a jak się przypisuje to zobacz wyżej.
tak, że uważam, że nie wracam żadnych wskaźników czy tablic dynamicznych które zostały utworzone lokalnie w tym obiekcie z

(*this) to rozumiem przez to że spod wskaźnika this wyłuskuje mi obiekt i do tego obiektu przypisuje

SH
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 6 lat
  • Postów:69
0

A odnośnie co robi destruktor
to jak najbardziej jest oczywiste, że zwalnia mi pamięć która została przydzielona na tablice dynamiczną
aczkolwiek wywołuje się za każdym razem gdy kończą się przeciążenia bo w każdym tworze sobie lokalne obiekty total

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:5 dni
0

Problem polega na tym że w wyniku wykonania
total& total::operator =(const int& i)
może powstać obiekt total z length==0 i tablicą znak==NULL
destruktor lub operator przepisanie takiego obiektu w niektórych implementacjach C++ może doprowadzić do błędu.
Tak a propos nie pokazałeś czym jest to twoje clear();

Zamiast:
(*this)=z;
return *this;
można napisać:
return operator=(z);
Zamiast:
(*this).clear();
(*this).realokacja(t.length);
można napisać:
clear();
realokacja(t.length);


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
SH
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 6 lat
  • Postów:69
0

moje clear()

jest w dwóch wersjach...

Kopiuj
void total::clear()
{
    //tworze nowa tablice z nowym rozmiarem
	unsigned int *NewTab = new unsigned int[1];
    
    znak = new unsigned int[1];
	//usuwam stara tablice
	delete []znak;
    NewTab[0] = 0;  //zeruje  element nowej tablicy
    znak=NewTab;
    length=1;
} 

Druga wersja

Kopiuj
 void total::clear()
{
    //zapamietuje poczatek starej tablicy
    unsigned int *tmp = &znak[0];
    //tworze nowa tablice z nowym rozmiarem
    znak = new unsigned int[1];

    znak[0] = 0;                    //zeruje  element nowej tablicy
    //usuwam stara tablice
    delete [] tmp;
    length=1;
}
0
Shial napisał(a):

A odnośnie co robi destruktor
to jak najbardziej jest oczywiste, że zwalnia mi pamięć która została przydzielona na tablice dynamiczną
aczkolwiek wywołuje się za każdym razem gdy kończą się przeciążenia bo w każdym tworze sobie lokalne obiekty total

Destruktor obiektu "z" zrobi delete [] znak. Czyli de facto tak jakby zrobił delete [] znak, na obiekcie, który zwracasz. Tzn. w tym nowym obiekcie znak wskazuje na zwolniony obszar pamięci.

SH
Dobrze ale tworząc obiek lokalny przypisuje go do (*this) co robi przepisanie tablicy operator przypisania patrz wyżej tak, że w nowym obiekcie znak nie wskazuje na zwolniony obszar pamięci. a jeżeli gdzieś widzisz miejsce w kodzie gdzie tak jest to proszę ukarz. może ja nie zauważyłem
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:5 dni
0

Pierwsza wersja do bani, bo nie zwalniasz obecnie przydzielonej pamięci na znak.
Druga wersja może być lecz lepiej ją zapisać następująco:

Kopiuj
void total::clear()
  {
    unsigned int *tmp=znak;
    znak=new unsigned int[length=1];
    *znak=0;
    delete[] tmp;
  }

Więc zakładam że błąd albo nie w tej klasie albo spowodowany operatorem przypisania int'a.
Właściwie to destruktorem lub metodą clear() wywołanymi po takim przypisaniu.
Sprawdź w swoim kompilatorze taki oto kod:

char *tmp=new char[0];
delete[] tmp;
char *tmp=new char[8];
delete[] tmp;

jeżeli powyższy kod spowoduje ten sam błąd to wina niepoprawnego przypisania, jeżeli nie szukaj w innym miejscu.

Tak a propos czy nie próbujesz zrobić operacji na dużych liczbach?
Jeżeli tak to raczej potrzebujesz unsigned char zamiast unsigned int.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
SH
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 6 lat
  • Postów:69
0

Operator przypisania inta masz powyżej w postach

Tak pisze operacje na dużych liczbach...
gruntem rzeczy mam napisane wszystko i działa... do momentu aż coś się nie stanie i nie wywala mi heap corruption

braku odpowiedzi na konsoli czy coś bo w tedy to już nie działa i się pitoli wszystko

przejrzyj to przypisanie bo ja wgl nie widze w nim błędu....

Kopiuj
 total& total::operator =(const int& i)
{
       total z;
       int length=0;
	   int b=i,c=i;
	   while (c) 
	   { 
		     length++; 
		     c/=10; 
	   }
       z.realokacja(length); 
       for(int j=0; j < length; j++)
	   {
               z.znak[j]=b%10;
               b=b/10;
	   }
 

(*this)=z; 
return *this;   
}
SH
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 6 lat
  • Postów:69
0

Próbuje już wszystkiego i nadal wywala mi error.... ;/

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:5 dni
0

Przecież ci powiedziałem, problem polega na tym że length=0 jeżeli i=0.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.