Prawidłowe zarządzanie pamięcia

0

Witam,
zastanawiam się jak najlepiej zarządzać pamięcią ? Piszę program, który ma konkretne limity i chce jak najefektywniej go napisać.

Mam kilkanaście zmiennych pomocniczych.
Czy rozsądnym jest każdą tworzyć przez ?

 int *variable = new int

czy po prostu pisać int variable = 0; ?

Z tego co wiem to pierwszy zapis powoduje zajęcie 8 bitów (4 na zmienną typu int i 4 na zmienną wskaźnikową typu int)

Oczywiście kiedy zmienna pomocnicza kończy swoje zadanie usuwam ją przez

delete(variable)

Nasuwa się też drugie pytanie. Czy lepiej tworzyć kilka zmiennych pomocniczych wykorzystując new i usuwać zaraz po tym jak zostaną wykorzystane czy po prostu stworzyć ją raz i wykorzystywać gdzie się da, a usuwać na końcu. Ta pierwsza opcja daje mi lepszą przejrzystość kodu bo mogę nazwać adekwatnie do zadania

I ostatnie wątpliwość. Co z iteratorami pętli ?

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

co dzieje się ze zmienną i po pętli ?

0

Nie ma co przydzielać pamięć pod pojedynczą zmienną, no chyba że to jest obiekt klasy (a nawet wtedy nie zawsze ma to sens).
Przydziela się pamięć pod tablicę
int *tb=new int[Rozmiar];
potem się usuwa:
delete[] tb;

Po takiej pętli (co podałeś) ta zmienna nie istnieje.

0

Tak jak jest napisane powyżej ... dla typów wbudowanych nie trzeba korzystać z operatora new().
Dla obiektów zdefiniowanych przez użytkownika możesz stosować new(), lub alokować je na stosie.
Zmienna i to zmienna lokalna (istnieje tylko w tej pętli). Przykład:

int main()
{
  {
    int a = 100;
    std::cout << a << std::endl;
  }
  //std:: cout << a << std::endl;  //blad - tutaj a już nie istnieje.
}
0

a czy inicjując int a = 100

można się jakoś tego pozbyć z pamięci ?

0

Po wyjściu z bloku rusza do pracy destruktor, nie ma już dostępu do zmiennej a.

0

@Fixus weź pod uwagę jedną rzecz:

  • pamięć zajmowana przez zmienne tworzone na zasadzie
int x;

a na zasadzie

int* x = new int;

to nie jest ta sama pamięć! Pierwsza to zmienne na stosie (który jest mocno ograniczony) a drugi to pamięć na stercie (dla uproszczenia można przyjąć że ogranicza ci ją zasadniczo ilość pamięci w komputerze)
Jak postanowisz na stosie zrobić gigantyczną tablicę żeby oszczędzić sobie te 4 bajty na wskaźnik to się moze okazać że program odmówi posluszeństwa bo miejsce na stosie się skończy.

0

Właśnie się uczę wskaźników więc podepnę się do tematu. A co dzieje się z pamięcią gdy mam przykładowo klasę która zawiera swoje zmienne składowe i tworzę do niej wskaźnik na zasadzie

nazwaClassy * pPointer=new nazwaClassy;

Wtedy cały obiekt wraz z składowymi klasy znajdują się na stercie czy jak?

0

Tak cała struktura/klasa na stercie, zaś na stosie masz tylko 4 bajtowy wskaźnik.

0

Ok czyli:

delete pPointer;

zwalnia całą pamięć użytą przez ten obiekt (nawet przez zmienne składowe które nie są wskaźnikami np int itsParametr )tak?
A co w wypadku gdy obiekt klasy jest alokowany na stosie i jego składowe są również wskaźnikami ,które w konstruktorze klasy otrzymują wartości początkowe które również znajdują się na stosie? Taki przypadek również znajduje się w mojej książce... Czym on się różni od poprzedniego?

0

Zwalnia całą pamięć zajmowaną przez sam obiekt. Ale jeżeli obiekt ma część dynamiczną to nie zwolni jej, z tym że tuż przed zwolnieniem tej pamięci ten delete wywoła destruktor obiektu (o ile został zdefiniowany) którego zadaniem jest zwolnić swoją część dynamiczną.

0

No wiem że w destruktorze obiektu zwalniamy dynamiczne składowe klasy ale nie widzę sensu używania takiej opcji... Czym się różnie 1 przykład od 2?

0
class Napis
  {
   private:
   char *str;
   public:
   Napis(const char *str):str(strdup(str)) {} // to samo rozpisane niżej
   // Napis(const char *str) { unsigned L=strelen(str)+1; str=new char[L]; memcpy(this->str,str,L); }
   ~Napis() { delete[] str; }
  };

int main()
  {
   Napis *s=new Napis("Ala ma kota");
   delete s; // bez destruktora pamięć przydzielona przez konstruktor nie zostanie zwolniona. 
   return 0;
  }
0

Trochę dla mnie nie zrozumiały kod ,bo 1 raz widzę takie polecenia w konstruktorze,ale przypuszczam że po prostu chodzi tam o inicjalizację składowej char*str;.

Po tym kodzie stwierdzam,że nie ma on w ogolę sensu... już lepiej napisać klasę z składowymi które nie są wskaźnikami bo to nam nic nie daje oprócz dodatkowych bajtów na wskaźniki bo nawet jeśli byśmy w destruktorze nie użyli polecenia delete[] str to i tak się nie odwołamy do tamtej składowej po usunięciu obietku klasy bo wskaźniki zostaną zniszczone i powstanie tzw. wyciek pamięci tak? Dobrze to rozumiem? Bo nadal nie widzę przeznaczenia tych składowych które są wskaźnikami.. Moim zdaniem jest to utrudnianie sobie kodu ,bo lepiej zastosować zwykłe zmienne i tak będą one znajdowały się na stercie jeżeli obiekt zaalokujemy na stercie racja?

0

@mto9 ale nie zawsze wygodnie jest ci tworzyć wszystkie obiekty na stercie. Zresztą często składowa klasy jest ciągiem znaków nieznanej w chwili kompilacji długości i wtedy użycie wskaźnika ma sens. Tak samo kiedy implementujesz jakąś strukturę danych typu lista czy drzewo, gdzie bez wskaźników jako składowych to jak bez ręki.

0

Ok ok już zczaiłem te wskaźniki i fajna sprawa z nimi ;D teraz tylko pisanie i pisanie aby do wprawy dojść ;d

1

@_13th_Dragon
Nie mieszaj strdup z delete []. strdup alokuje pamięć pod nową tablicę za pomocą malloca, a delete gwarantuje usunięcie pamięci zaalokowanej przez new. Akurat gcc domyślnie używa malloca przy operatorze new, ale ogólnie nie powinno się mieszać tych dwóch metod alokacji.

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