Heap Corruption

0

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

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

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

 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

 total z //wynik

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

(*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 ??

0
 

 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...

 

 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ą.

0

jak nie zwalniam jak

 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

     unsigned int *tmp = &znak[0];

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

 delete [] tmp; 

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

0

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

total a 

i potem wywołam na nim

 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

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.

0

To są moje operatory przypisania.

 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ę

 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
 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):
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):
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.

0
 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

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

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);

0

moje clear()

jest w dwóch wersjach...

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

 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.

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:

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.

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....

 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

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

0

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

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