[VC] delete

0

Dlaczego, jak usuwam obiekt dynamiczny przez delete w VC++ (6 Std.) to mi wywala accessa? :(
Podobno kompilator i tak usuwa na zakończenie pracy obiekty, ale jeżeli ja chcę zwolnić wcześniej pamięć, to się wykrzacza. Przed usunięciem sprawdzam, czy obiekt istnieje, a on swoje.
Ktoś wie dlaczego tak jest?

0

Obiekt dynamiczny nie bedzie usuwany po zakonczeniu programu w C++ :> Zmienna (obiekt) automatyczny to co innego :)
Jesli sam zrobiles obiekt za pomoca new to i sam musisz go zwolnic - tego kompilator nie zrobi za ciebie ( w Javie zrobilby to garbage collector ale w C++ jest inaczej ;) ).
Sprawdz dokladnie czy na pewno dobrze zostal stworzony obiekt i czy destruktor nie jest zepsuty ;)
Najlepiej zapodaj konstruktor, destruktor sposob tworzenia i zwalniania.

Access nie powstaje sam z siebie musiales kompa czyms wkurzyc :]

0

Obiekt dynamiczny nie bedzie usuwany po zakonczeniu programu w C++ :>

Zapisać sobie: "sprawdzać to co mówi Łupińska" ;) Miła kobieta, ale z tego co zdążyłem zauważyć, to na programowaniu się nie zna (ale chyba na piciu tak...)

Wracając do problemu. Main:

int main(int argc, char* argv[])
{
	CComplex *M1;

	M1 = new CComplex(1, 1);
	delete m;
	getchar();

	return 0;
}

Klasa CComplex:

class CComplex : public CMatrix
{
public:
	void Print();
	void Insert();
	CComplex *Mul(CComplex *c);
	CComplex *Sub(CComplex *c);
	CComplex *Add(CComplex *c);
	CComplex(CMatrix *c1, CMatrix *c2, int row, int col);
	CComplex(int row, int col);
	virtual ~CComplex();

private:
	int FRow;
	int FCol;
	CMatrix* FReMacierz;
	CMatrix* FImMacierz;
};

Implementajca konstruktorów i destruktora:

CComplex::CComplex(int row, int col)
{
  FReMacierz = new CMatrix(row, col);
  FImMacierz = new CMatrix(row, col);
  FRow = row;
  FCol = col;
}

CComplex::CComplex(CMatrix *c1, CMatrix *c2, int row, int col)
{
  FReMacierz = c1;
  FImMacierz = c2;
  FRow = row;
  FCol = col;
}

CComplex::~CComplex()
{
	if (FReMacierz)
		delete FReMacierz;
	if (FImMacierz)
		delete FImMacierz;
}

Klasa CMatrix:

class CMatrix  
{
public:
	float Element(int i, int j);
	void Insert();
	void Print();
	CMatrix* Mul(CMatrix *m);
	CMatrix* Sub(CMatrix *m);
	CMatrix* Add(CMatrix *m);
	CMatrix(int row, int col);
	CMatrix();
	virtual ~CMatrix();

private:
	float** FArray;
	int FRow;
	int FCol;
};

Implementacja konstruktorów i destruktora:

CMatrix::CMatrix(int row, int col)
{
	FRow = row;
	FCol = col;
	FArray = new float*[FRow];
	for (int i=0; i<FRow; i++)
		FArray[i] = new float [FCol];
}

CMatrix::CMatrix()
{
}

CMatrix::~CMatrix()
{
	for (int i=0; i<FRow; i++)
		if (FArray[i])
		delete FArray[i];
	if (FArray)
		delete FArray;
}

Będę wdzięczny za pomoc.

0

Ehhh Dryo a ja glupi siedze i nie wiem dlaczego ~CMatrix wywoluje sie 3 razy (umiejetnosc poslugiwania sie debagierem VC++ to blogoslawienstwo [diabel] ) a nie 2 az tu nagle widze : class CComplex : public CMatrix !!!!!
Nie wiem po co w tym programie dziedziczenie :> ale zeby to dzialalo musisz zmienic konstruktor:
[code]
CMatrix::CMatrix()
{
FArray= NULL;
}
[/code]
Dryo domyslam sie ze wiesz juz dlaczego tak trzeba zrobic ;)
W konstruktorze CComplex (klasie pochodnej) przy tworzeniu nowego obiektu odpalany jest zawsze konstruktor klasy bazowej czyli CMatrix, poniewaz nie podales jaki ma byc dokladnie odpalany odpalany jest domyslny czyli CMatrix(). Oprocz tego ofcoz pozniej tworzone sa kolejne 2 obiekty CMatrix.
Juz nie ma Accessa :d

0

Taaa debagier. W porównaniu do borlandowskiego debbugera, to ten wysiada.
Jak chciałem krok po kroku zagłębić się w usuwanie obiektu (F11), to mi się wykrzaczał i tylko zrzut pamięci mi dawał :( Jak stawiałem breaki wewnątrz destruktorów to nawet nie docierało do nich :(
Dlaczego dziedziczenie? Pierwszy obiekt miał działać na macierzach liczb rzeczywistych, a drugi na zespolonych. Taki przykład właśnie dziedziczenia. Później pewnie każe nam zrobić przeciążenia operatorów (IMHO najfajniejsza rzecz w C++) itp.
Już nie mogę się doczekać Javy i normalnego borlandowskiego środowiska... Wiem, wiem, narzekam. Ale przyzwyczaiłem się do zabawek Borlanda :)

Dzięki snaj. Pewnie z VC++ jeszcze cię trochę pomęczę...

0

Jakos mi sie nie wierzy zeby Borland mial lepszego debugera, a tak jak pisalem tego z M$-a trzeba umiec obslugiwac i mozna z jego pomoca wejsc tam gdzie wzrok nie siega [diabel] to jest potezzna maszyna.
Ty czekasz az na polibudzie dadza Ci Borlanda, to przestan czekac tylko cwicz VC++ i nic wiecej zadne automaty (buildery) nie wchodza w rachube :]

0

To powyzej to ja. Ehh ale to forum jest .... :-/ porazka.

Co do dziedziczenia nadal twierdze ze jest to zly przyklad. Laczenie dziedziczenia i kompozycji w ten sposob co zrobiles jest bledne. CComplex dziedziczysz z CMatrix a potem w nim umiszczasz jeszcze obiekty CMatrix. W takim wypadku staosuje badz dziedziczenie badz kompozycje, ale oddzielnie obie definicje sa wyraznie rozne :-8 i maja swoje odpowiedniki z zycia (jakikolwiek manual dobrze to opisuje).

0

co do twoich zarzutów co do VS i jego debugera to chyba swiadczy ze zbyt malo jeszcze znasz mozliwosci VC aby go docenic
a teraz male wskazowki ci co znaja debugera VC prosze nie czytac bo to dla tych ktorzy nie znaja go za dobrze i chca sie nauczyc czegos nowego (lub nie chca a tylko narzekaja ze jest do d**y)

  1. jak masz accessa tzn ze najprawdopodobniej jest to twoja wina a nie VC

  2. jesli chcesz sie dowiedziec co bylo przyczyna to uzyj Context (z okna Variable), dzieki czemu bedziesz mogl zobaczyc jakie metody zostaly pokolei wywolane, przesuwajac sie w po nim i klikajac dotrzesz do miejsca gdzie jest blad (w przypadku problemu Dyrobates'a do destruktora klasy CMatrix)

  3. a teraz jak poznac ze cos jest nie tak, otóż visual robi bardzo fajne rzeczy np. jezeli pod zmienna nie zostala wpisana jeszcze zadna wartosc to znjadziemy w niej ciag 0xcdcdcdcd (tutaj przyklad zmiennej 4 bajtowej dla 2 bajtow np. short int bedzie oczywiscie 0xcdcd), w w przypadku problemu Dyrobates'a w nieszczesnym destruktorze ujrzymy ze wartosc zmiennej FArray==0xcdcdcdcd co oznacza ze nie zostala do niej przypisana zadna wartosc. a wiec
    FArray = new float*[FRow];
    nie zostalo wywolane (bo gdyby nawet nie powiodlo sie zarezerwowanie pamieci (np. z jej braku :) to wtedy FArray==NULL)

  4. a teraz przyklad z innej beczki

#include <stdio.h>
int main(int argc, char* argv[])
{
int *pData;
pData=new int[100];
delete[] pData;
delete[] pData;
return 0;
}

jak widac celowo zwalniam przydzielona pamiec dwa razy, (po co ??) aby pokazac jak poznac ze pamiec zostala wczesniej juz gdzies zwolniona.
no i znow mamy assercik, a wiec do Context i przechodzimy do main tam gdzie zostal wywolany drugi raz nieszczesny delete. jak widac pData ma jakas sensowna wartosc (pewnie bosmy NULL pod nia nie podstawili gdy zwolnilismy ja pierwszy raz) ale wystarczy zagladnac co sie kryje pod pData (klikajac na krzyrzyk przy nim), a pod adresem wskazywanym przez pData mamy 0xdddddddd, co to oznacza najprawdopodobniej ano ze pamiec przydzielona pod tym adresem zostala juz zwolniona wczesniej (jest jescze jedna mozliwosc sami wpisalismy tam 0xdddddddd ale wtedy nie mamy assserta :) )

  1. jak podejrzec N elementow tablicy. a wiec mamy oto taki programik

#include <stdio.h>
#include <conio.h>
#define NoElements 100
int main(int argc, char* argv[])
{
int k,pData;
pData=new int[NoElements];
for(k=0;k<NoElements;k++){
pData[k]=k
100;
}
k=3;
printf("%ld",pData[k]); //breakpoint tutaj
if(pData!=NULL){
delete pData;
pData=NULL;
}
getch();
return 0;
}

jak widzimy nareszcie zwolnienie pamieci dla tablicy pData jest poprawne :)
ustawmy teraz breakpointa w oznaczonym miejscu, gdy program sie zatrzyma wpiszmy do watch'a 'pData'(uwaga wpis bez apostrofow) . a teraz zobaczmy co sie znajduje w pamieci zarezerwowanej dla pData (klikajac plusik), niesty widzimy tylko pierwszy element który jest rowny 0, ok a teraz wpiszmy do watch'a 'pData,10' i znow podejrzyjmy co sie znajduje w pamieci ,nareszcie mamy podglad 10 elementow naszej tablicy

  1. Modyfikowanie wartosci zmiennych z pod debugera podczas pracy programu.
    poniewaz juz wiemy jak wyswietlic N elementow tablicy w watch'u to teraz dowiemy sie jak zmieniac wartosc zmiennych podczas dzialania programu za pomoca watch'a. do tego posluzymy sie przykladem programu powyzej. ustawiwmy znowu breakpointa tam gdzie poprzednio. podgladamy jaka wartosc ma zmienna k (oczywiscie ze jest to 3) wpisujemy do watch'a 'k'. jak widzimy w nastepnym kroku program wyswietli nam wartosc pData[3], a my w tym momencie chcemy to zmodyfikowac gdyz juz teraz wiemy ze ma to byc pData[7], a wartosc pod k jest zla, w takim wypadku nalezy wpisac do watch'a 'k=7' i wcisnac enter. potem nalezy usunac to z watch'a chyba ze chcemy aby za kazdym krokiem debugera byla podstawiana ta wartosc.

7.Modyfikacja kodu programu podczas jego dzialania.
zadanie z punktu 6 czyli wypisanie pData[7], a nie pData[3] mozemy takze zrealizowac w inny sposob, poprzez zmodyfikowanie kodu programu podczas jego wykonywania. a wiec znow ustawiamy breakpointa w programie z punktu 5. kiedy program sie zatrzyma to podmieniamy linie kodu
printf("%ld",pData[k]);
na
printf("%ld",pData[7]);
i puszczamy go dalej, po skompilowaniu wykona sie juz zmieniona wersja kodu oczywiscie od miejsca w ktorym byl ustawiony breakpoint.
8.Jeszcze raz modyfikacja kodu podczas dzialania programu (lecz bardziej ekstremalana :)). tym razem posluze sie nowym kodem :)

#include <stdio.h>
int main(int argc, char* argv[])
{
while(1){
printf("pierwszy tekst\n");
}
return 0;
}

uruchamiamy program i pozwalamy aby dzialal. jak widzimy wyswietla on caly czas text 'pierwszy tekst'. kiedy program zajmuje sie pracowitym drukowniem kolejnych linijek tekstu my wracamy do VC nie konczac oczywiscie programu i perfidnie po cichu zmieniamy w kodzie
printf("pierwszy tekst\n");
na
printf("inny tekst\n");
jak juz to zrobimy to wciskajac Alt+F10 przekompilowujemy nowy kod i podmieniamy go, jezeli wrocimy do programu to ujrzymy ze wypisuje on juz
'inny tekst' (nawet sie nie zorientowal jak podmienilismy jego czesc hihi :))

na dzisiaj starczy (pozno juz),
jak znajde troche czasu to opisze inne fajne rzeczy w debugerze VC.
PS.(bede uszczypliwy :))panowie od BC moze napiszecie jak sie tkie rzeczy robi w debugerze BC (jak napiszecie to wtedy rzuce pare nastepnych sztuczek (moze troche trudniejszych))

0

Jaki gosc :-)
Ja tylko wspomne o okienkach diassemblera, podgladu rejestrow, stosu, pamieci procesu, okienku zagniezdzenia funkcji. WYPAS :d

0

snaj: to nie mój pomysł z tym dziedziczeniem. Jak dla mnie to jest ono tutaj zbęde, bo przecież nic poprzedniej klasy nie wykorzystujemy. Ale ja tylko polecenia wykonuję. Mi to wsio ryba co dają mi do zrobienia. Ma działać.

gees: fakt. VC znam mało, a do różnych narzędzi Borlanda się już przyzwyczaiłem (F9 do tej pory naciskam...). Przyzwyczajenie się jest pewnie kwestią czasu.

Ad. 1 Wina zawsze jest po stroni programisty, nie tylko przy accesie. Błędy w kompilatorach to naprawdę rzadkość. Ale tak to już jest, że jak człowiekowi coś nie wychodzi to musi zwalić na coś innego. Zwłaszcza, jeżeli nie jest się z tym zaznajomionym lub nie ma do tego dokumentacji ;(
Ad. 2 Do tego doszedłem już przy pierwszym uruchomieniu stawiając breakpointa przed delete, ale nie mogłem się zagłebić...
Ad. 3 Widziałem też 0xcccc wartości. Dzięki. Dobrze wiedzieć, że VC inicjaizuje na takie wartości zawsze (a nie śmieci).
Ad. 4 Czy VC fizycznie podpisuje pod zmienną taką wartość przy zwalnianiu (tzn. dddd)? Czy może to jedynie w debuggerze dla ułatwienia jest tak kodowane?
Ad. 5 To chyba w pascalu jest najlepiej zrobione, ale to ze względu na specyfikę języka.
Ad. 6-8 Dzięki. W Borlandowskich środowiskach jest do tego evaluate/modify.

0

Ad. 4 Czy VC fizycznie podpisuje pod zmienną taką wartość przy zwalnianiu (tzn. dddd)? Czy może to jedynie w debuggerze dla ułatwienia jest tak kodowane?
tu chodzi o delete w debug'u
ale nie tylko 0xdddddddd , moze tez byc np 0xfdfdfdfd wiem ze czyms sie róznia ale nie wiem dokladnie kiedy wpisuje oxdd a kiedy 0xfd (moze ktos wie)

i dokladnie tez nie wuiem jaka jest roznica pomiedzy 0xcd a 0xcc (moze tez ktos wie)

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