Zarządzanie pamięcią - przeładowane operatory new i delete

Żadna zarządzana pula obiektów, nie przyspieszy w taki sposób alokacji pamięci dla małych obiektów, choćbyś na uszach stanął.

A Ty jesteś niby tym zającem? No to już teraz wiem, dlaczego więcej piszesz niż myślisz.

Tak ale nie wiem jak mam tworzyć takie tablice. Tzn, mógłbym na przykład utworzyć dwuwymiarową, np:

bool obszar[10][100];

tylko właśnie nie wiem jak to rozwiązać jak przekroczę 100 obiektów i trzeba będzie zrobić rezerwację na następne 100 obiektów. Bo np. ta tablica co powyżej zakłada, że może być tylko 10 takich rezerwacji. Mógłbym to też zrobić tak, że tworzę tablicę new’em ale potem myślę, że na 100% bym się pogubił…

Quentin , możę do końca ten mój post doczytaj. Jeżeli jak czegoś nie zrozumiałeś to dopytaj. Na początek radzę nie przejmować się przekroczeniem 100 szt, jak wszystko zajęte to zwracasz 0 - brak pamięci.

Wybrałem wersję z tablicą bool. Tak jak przedtem w main() są przykładowe użycia - testowałem to trochę i myślę, że teraz to działa…

#include 

using namespace std;


///////////////////////////////////////////////////////////////////////////////////////

class wektor

{

public: 

	//Składniki są public bo niektóre potrzebuję do main na rzecz tego przykładu

	//potem można je oznaczyć jako private (a nawet powinno się)

	int x, y;

	static bool rezerwacja[99];

	static char *wsk;

	static int size;

	static bool czy_pierwszy_raz;


public:

	//------------konstruktor

	wektor(int a = 0, int b = 0) : x(a), y(b)

	{ }


	static void* operator new(size_t rozmiar);

	static void operator delete(void *co_skasowac);


};

///////////////////////////////////////////////////////////////////////////////////////

bool wektor::czy_pierwszy_raz = true;

bool wektor::rezerwacja[99];

char* wektor::wsk = 0;

int wektor::size = sizeof(wektor);	//(dzięki tej zmiennej nasze operatory zadziałają w każdej klasie)

// *************************************************************************************

void* wektor::operator new(size_t rozmiar)

{

	if(czy_pierwszy_raz)

	{

		wsk = new char[rozmiar * 100];

		czy_pierwszy_raz = false;

	}

	//-------------------------------------------

	int ktory;

	for(ktory = 0 ; ktory < 100 ; ktory++)

	{

		if(rezerwacja[ktory] == 0) break;	//0 - wolny

	}

	if(ktory == 100) //jeżeli wszystkie są zajęte

	{

		cout << "\t####Obiekt nie jest tworzony - wykorzystales pamiec !\n";

		return 0;

	}

	rezerwacja[ktory] = 1;

	return wsk + (ktory * size);


}

// *************************************************************************************

void wektor::operator delete(void *co_skasowac)

{

	int ktory;

	for(ktory = 0 ; ktory < 100 ; ktory++)

	{

		if(rezerwacja[ktory] == 0) break;	//0 - wolny

	}

	if(ktory == 100) //czyli jeżeli cały blok jest zapełniony to są dwie możliwości

	//- jeśli kasujemy ostatni obiekt delet'em (np. tablica[99]) to kasujemy całą rezerwację

	//- jeśli kasujemy NIEOSTATNI obiekt delet'em - to oznaczamy to miejsce jako wolne

	{

		int i = 0;

		for( ; i < 800 ; i+=8)	//szukamy naszego adresu

		{

			if(wsk + i == co_skasowac) break;

		}

		if(i == 792)	//jeśli jest ostatni - kasujemy wszystko

		{

			delete wsk;	

			for(int i = 0 ; i < 100 ; i++)

			{

				rezerwacja[i] = 0;

			}

			czy_pierwszy_raz = true;

			return;	//kończymy (żeby nie wykonała się ostatnia pętla for)

		}


	}

	for(int i = 0 ; i < 800 ; i+=8)

	{

		if(wsk + i == co_skasowac) 

			rezerwacja[i / 8] = 0; //wolny

	}


}

// *************************************************************************************



int main()

{


	/*

	wektor* tablica[5];

	tablica[0] = new wektor;

	tablica[1] = new wektor;

	tablica[2] = new wektor;

	tablica[3] = new wektor;

	tablica[4] = new wektor;


	for(int i = 0 ; i < 10 ; i++) //do dziesięciu - więcej nie trzeba

	{

		cout << wektor::rezerwacja[i];	//1111100000

	}


	//########################################################

	cout << "\n\n";


	delete tablica[2];

	delete tablica[0];


	for(int i = 0 ; i < 10 ; i++) 

	{

		cout << wektor::rezerwacja[i];	//0101100000

	}


	//########################################################

	wektor* nowy_obiekt = new wektor;


	cout << "\n\n";


	for(int i = 0 ; i < 10 ; i++) 

	{

		cout << wektor::rezerwacja[i];	//1101100000

	}

	*/



	/*

	//################################ DRUGI PRZYPADEK ################################

	wektor* tab[100];

	for(int i = 0 ; i < 100 ; i++)

	{

		tab[i] = new wektor;

	}


	for(int i = 0 ; i < 100 ; i++) 

	{

		cout << wektor::rezerwacja[i];	//cały ekran jedynek - wszystko zapełnione

	}


	delete tab[67]; //nie kasowaliśmy ostatniego więc nie skasuje się cała rezerwacja

	//- tak jest tylko dla:

	//delete tablica[99] !


	cout << "\n\n";

	for(int i = 0 ; i < 100 ; i++) 

	{

		cout << wektor::rezerwacja[i];	//cały ekran jedynek i jedno zero

	}

	*/


}[/code]

No i co - dobrze to zrealizowałem :?:

Kompletny bezsens :x

static bool rezerwacja[99]; - ile ma elementów ta tablica?

Naprawdę, a ja myślałem że kasujemy ostatni kiedy tylko jedna rezerwacja zajęta i właśnie tą rezerwację kasujemy.

Czyżby zapomniałeś o zmiennej size?

Kto ci powiedział że ten ostatnio przydzielony zostanie zwolniony jako pierwszy? Absolutnie błędne założenie.

Czy nie prościej obliczyć nr elementu do kasowania następująco:

który=(co_skasowac-wsk)/size;

na wszelki wypadek sprawdzić czy który jest w granicach 0…99 oraz czy co_skasowac==wsk+(który*size) oraz czy rezerwacja[ktory]==true.

Jeżeli coś się nie zgadza to znaczy że ktoś próbuje zwolnić coś czego nie przydzielał.

Na koniec tylko jedna pętla sprawdzająca czy przypadkiem nie ostatni zwolniono.

Na brak pamięci nie piszę się tekstów: albo assert() albo wyjątek albo cicho zwracasz 0.

Albo jesteś przemęczony albo coraz gorzej ci z programowaniem idzie :lol:

Powinno być coś w stylu:

#include using namespace std;

Mój błąd.

Nie rozumiem za bardzo o co Ci chodzi ze zwalnianiem “jako pierwszy”: jeżeli i == 792 tzn., że kasujemy obiekt ostatni i jak już przyjąłem wtedy kasuje się cała rezerwacja. Mogę to zmienić aby rezerwacja się zwalniała kiedy używamy “byle jakiego” delete, ale wtedy kiedy wszystkie obszary są zajęte. Zauważ tylko co pisze w poleceniu w ćwiczeniu, które napisałem w moim 1-szym poście…

Tego też jeszcze nie wiedziałem.

W zadaniu napisano że masz poprawnie zarządzać przydzielonym obszarem pamięci. Stąd założenie że zwolnienie obszaru który został przydzielony jako ostatni jest sygnałem że zwolnione już wszystkie jest jak najbardziej błędnym.

U ciebie jak stworzysz 100 obiektów a potem zwolnisz tylko ostatni z nich to operator delete zwolni wszystko.

Aha już rozumiem, jakbym kasował nie-końcowy obiekt, delete tab[56], delete tab[3] a potem końcowy to skasowałby się dwa razy ten sam obszar, czyli za 2-gim razem przypadkowe miejsce jakieś.

Nie. Jak dałeś delete tab[3]; to nic się nie skasowało jedynie zostało zaznaczone. Ale po przydzieleniu for(i=0;i<100;++i) tab_=new wektor; jeżeli dasz delete[] tab[99]; to twój operator delete zwolni wszystko, cały obszar dla tab[0], tab[1], tab[2] … tab[98] no i tab[99] też._

Tak, rzeczywiście, już mi się trochę to pomieszało.

I to właśnie było moim zamiarem. Załóżmy, że ktoś zrobił sobie 100 elementową tablicę obiektów tej np. mojej klasy wektor. Załóżmy też, że ma ona bardzo dużo składników. I 99 obiektów jest mu potrzebnych, a jeden może usunąć bo się np. w czymś pomylił. Te 99 pozostałych obiektów jest dobrze opracowane i ktoś się na tym sporo narobił. I teraz może usunąć ten zły np.: delete tab[67]__:

:arrow: jeśli miał wersję moją wcześniejszą (oczywiście z poprawionym tym składnikiem, że zamiast [99] jest [100]) to może sobie spokojnie usunąć ten obiekt i stworzyć następny, już poprawny na tym samym miejscu (to było pokazane w main() w “Drugim przypadku” i oczywiście działa to poprawnie),

:arrow: jeśli miał wersję tą niby lepszą to skasuje mu się wszystko. Niby może zrobić znowu te 100 obiektów i pobawić się w kopiowanie, ale jak już mówiłem przy tych 99 trochę się napracował…