C++ - 10. lekce
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
Reklama

C++ - 10. lekceC++ - 10. lekce

 

C++ - 10. lekce

Google       Google       16. 7. 2005       52 940×

  • alokace paměti pomocí operátoru new
  • uvolnění paměti pomocí operátoru delete
  • upozornění na práci s pamětí
  • úkol č.10

Reklama
Reklama

Nyní byste měli mít jistý pocit, jak ukazatelé pracují. Ovšem pojďme dále - alokování paměti za běhu programu.

Doposud jste inicializovali proměnné adresami proměnných. Co to jsou tedy proměnné? Pojďme si to zopakovat. Proměnné jsou pojmenovanou pamětí alokovanou v době kompilace. Ukazatele pouze poskytují druhé jméno pro paměť, ke které byste mohli přistupovat podle jména. K čemu tedy ukazatele? Pravá cena ukazatelů vyplouvá na povrch, když alokujete nepojmenovanou paměť na úschovu hodnot v době běhu programu. V tomto případě se k paměti dostanete pouze pomocí ukzatelů. Pokud jste se dříve učili C, mohli jste paměť alokovat pomocí f-ce malloc() - to stále můžete, ale C++ má lepší způsob - operátor new

Alokace paměti pomocí operátoru new

Takže jak na to?
Zkusíme si vytvořit nepojmenovanou paměť za běhu programu pro hodnotu typu int a budeme k ní přistupovat pomocí ukzatele. Poskytneme operátoru new typ dat, pro kterou chceme paměť, new nalezne blok správné velikosti a navrátí jeho adresu, tu přiřadíme ukazateli.

int * vek = new int

Tento příkaz říká programu, že chceme novou paměť vhodnou pro úschovu int. Jakmile ji nalezne, vrátí jeho adresu a ta se přiřadí do vek - což je typ ukazatele na int. Nyní je tedy vek adresou a * vek hodnotou uložené na dané adrese. Ukazatele se vám možná jeví nešikovně, ale máte větší pohled nad tím, jak váš program spravuje paměť. Ukažme si tedy obecný tvar:

jmeno_typu jmeno_ukazatele = new jmeno_typu

Poprvé určujete datový typ (int) požadované paměti a podruhé deklaraci vhodného ukazatele.


#include <iostream>
using namespace std;
int main()
{
  int * promenna = new int; // alokuje prostor pro int
  *promenna = 1001; // uloží tam hodnotu
  cout << "int hodnota = " << *promenna << ": umisteni = "
  << promenna << "
";
  double * promenna2 = new double; // alokuje prostor pro double
  *promenna2 = 10000001.0; // uloží tam double
  cout << "double hodnota = " << *promenna2 << ": umisteni = " 
  << promenna2 << "
";
  cout << "velikost promenna = " << sizeof promenna;
  cout << ": velikost *promenna = " << sizeof *promenna << "
";
  cout << "velikost promenna2 = " << sizeof promenna2;
  cout << ": velikost *promenna2 = " << sizeof *promenna2 << "
";
  cin.get();
  return 0;
}
A výsledek :

int hodnota = 1001: umisteni = 00420750
double hodnota = 1e+007: umisteni = 00420710
velikost promenna = 4: velikost *promenna = 4
velikost promenna2 = 4: velikost *promenna2 = 8

Ukazatele promenna a promenna2 ukazují na dva datové objekty - bez nich nemůžete k tmto paměťovým lokacím přistupovat. Zde také vidíme, proč musíme deklarovat typ, na který ukazatel ukazuje. Adresa odhalí jen začátek, kde je objekt uložen - jak vidíte, velikost ukazatele na int i double je stejná. Ale protože jsme deklarovali typy ukazatelů, program ví, že promenna2 má 8 bajtů.

Mimo rozsah paměti?
Pokud počítač nemá dostatek volné paměti, vrací hodnotu 0* => prázdný ukazatel. C++ zaručuje, že prázdný ukazatel nikdy neukazuje na platná data, takže se často používá na indikování selhání operátorů či f-cí, které jinak navracejí nepoužitelné ukazatele.

* pan Mirek Virius doplňuje:
Podle standardu ISO 14882-2003 operátor new v základní podobě nevrací při neúspěchu 0, ale vyvolává vyjímku ntypu std::bad_alloc. Chceme-li, aby vracel 0, musíme použít podobu new(nothrow) (a předtím uvést #include).

Možná stále nerozumíte - "proč bych měl používat něco, co je zbytečné, těžké... proč bych měl pracovat s nepojmenovanou pamětí, když můžu jednoduše pracovat s proměnnou?"
Odpověď je jednoduchá - klasické proměnné alokují paměť v době kompilace, kdežto alokovaná paměť pomocí operátoru new se alokuje ZA běhu programu - tedy pouze tehdy, pokud bude využita, potřebná... Klasická proměnná se vždy "přihlásí" o své místo na začátku běhu programu. Ale co když nepotřebujete tolik proměnných? Co když se ukáže, že některé proměnné nebudou za celý běh programu ani jednou využity? Myslíte si, že to není možné? A co podmínky? Jestliže uživatel zadá ano, provede se určená část programu. Takže možnost "ne" zůstane neupotřebena a veškerý následující kód po této podmínce nebude upotřeben - ani proměnné. Tedy zbytečně jste plýtvali místem. Kdežto při alokaci paměti během programu se vám toto nestane - paměť se alokuje pouze tehdy, je-li to nutné. Možná si říkáte, proměnné jsou jednodušší..., ale vy si nemůžete poté u složitějších programů plýtvat pamětí!! Určitě vás u nových her štve, že mají takové hardwarové nároky. Takže neučte se zavrhovat a odsuzovat alokoci paměti za běhu programu, naopak, naučte se to používat. No a proč tedy ukazatele? No přeci proto, abyste nějak mohli s danou pamětí pracovat. Tedy:
Pojmenovaná paměť - int a - můžeme se na ní odkázat jménem proměnné nebo ukazatelem na proměnnou.
Nepojmenovaná paměť - int vek = new int - můžeme se na ni odkázat pouze ukazatelem

Uvolnění paměti pomocí operátoru delete

Mysleli jste si, že alokujete paměť za běhu programu a konec? Ne, tak jednoduché to není. Klasická proměnná je po ukončení programu zničena (uvolněna), ale paměť alokovaná za běhu programu zůstává i nadále po ukončení progrmu alokována, není uvolněna!

Pamatujte, takto alokovanou paměť (pomocí operátoru new) VŽDY uvolněte pomocí operátoru delete!

Takto uvolněná paměť může být poté znova použita jinou částí vašeho programu. Jedná se o nejefektivnější využití paměti.


int * promenna = new int;   //alokace paměti pomocí new
delete promenna;   //uvolnění paměti pomocí delete

Toto odstraňuje paměť, na kterou ukazuje promenna, neodstraňuje to samotný ukazatel. Můžete ho znovu použít, aby ukazoval na jinou lokaci. Dále byste se neměli pokoušet uvolňovat blok paměti, který jste již uvolnili - výsledek není definován.


int * promenna = new int;   //ok
delete promenna;   //ok
delete promenna;   //chyba - již uvolněná paměť
int vek = 5;   //ok
int * cil = & vek;   //ok
delete cil;   //chyba - paměť nebyla alokována pomocí new

Upozornění:
Používejte delete pouze k uvolnění paměti alokované pomocí new a zapamatujte si, že je bezpečné aplikovat delete na nulový ukazatel.

Rozhodujícím testem na použití delete je to, že ho použijete na paměť alokovanou pomocí new. To znamená, že nepotřebujete použít stejný ukazatel k uvolnění paměti, který jste použili u new:


int * promenna = new int;   //alokuje paměť
int * prom = promenna;   //nastavuje druhý ukazatel na stejný blok
delete prom;   //uvolníte paměť pomocí druhého ukazatele

Obyčejně dva ukazatele na stejný blok paměti nechcete vytvořit, protože tím vzrůstá pravděpodobnost, že se chybně pokusíte uvolnit stejný blok 2×. Ale jak brzy uvidíte, použití druhého ukazatele má smysl, když pracujete s f-cí, která navrací ukazatel.

Úkol č.10

Bude lehký - alokujte 2× int, 1× double a 1× float(ne jako proměnné, ale pomocí operátoru new), nechte do nich uživatele zadat hodnoty a poté se ho zeptejte, zda bude potřebovat danou paměť, pokud ne, paměť se uvolní, pokud ano, nabídnete mu přepsání stávajících hodnot. A tak dokola, dokud uživatel neuzná data za zbytečná a dá uvolnit. Jakmile dá uvolnit, vypíšou se napsaná čísla. Budete tedy muset čísla nakopírovat do klasických proměnných.

V příští lekci se naučíte vytvářet dynamická pole pomocí operátoru new a jejich použití.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

Hlasování bylo ukončeno    
0 hlasů
Google
(fotka) Lukáš ChurýLukáš je šéfredaktorem Programujte, vyvíjí webové aplikace, fascinuje ho umělá inteligence a je lektorem na FI MUNI, kde učí navrhovat studenty GUI. Poslední dobou se snaží posunout Laser Game o stupeň výše a vyvíjí pro něj nové herní aplikace a elektroniku.
Web     Twitter     Facebook     LinkedIn    

Nové články

Reklama
Reklama
Obrázek ke článku Nový IT hráč na českém trhu

Nový IT hráč na českém trhu

V roce 2015 otevřela v Praze na Pankráci v budově City Tower své kanceláře společnost EPAM Systems (NYSE:EPAM), jejíž centrála se nachází v USA. Společnost byla založená v roce 1993 a od té doby prošla velkým vývojem a stále roste.

Obrázek ke článku České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace (CRA) pořádají druhý ročník CRA IoT Hackathonů. Zájemci z řad vývojářů a fanoušků moderních technologií mohou změřit své síly a během jediného dne sestrojit co nejzajímavější funkční prototyp zařízení, které bude komunikovat prostřednictvím sítě LoRa. CRA IoT Hackathony se letos uskuteční ve dvou fázích, na jaře a na podzim, v různých městech České republiky. Jarní běh se odstartuje 31. března v Brně a 7. dubna v Praze.

Obrázek ke článku Cloud computing je využíván stále intenzivněji

Cloud computing je využíván stále intenzivněji

Využívání cloud computingu nabývá na intenzitě. Jen v letošním roce vzroste podle analytiků trh se službami veřejného cloudu o 18 %, přičemž o téměř 37 % vzrostou služby typu IaaS. Růst o více než pětinu pak čeká služby poskytování softwaru formou služby, tedy SaaS. Aktuálním trendům v oblasti využívání cloudu se bude věnovat konference Cloud computing v praxi, která se koná 23. března. 2017 v pražském Kongresovém centru Vavruška na Karlově náměstí 5.

Reklama autora

loadingtransparent (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })();
Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032017 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý