PB161 Programování v jazyce C++ Přednáška 5

Podobné dokumenty
PB161 Programování v jazyce C++ Přednáška 5

PB161 Programování v jazyce C++ Přednáška 4

PB161 Programování v jazyce C++ Přednáška 8

PB přednáška (12. října 2015)

PB161 Programování v jazyce C++ Přednáška 4

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

PB161 Programování v jazyce C++ Přednáška 9

PB161 Programování v jazyce C++ Přednáška 9

PB161 Programování v jazyce C++ Přednáška 9

Ukazatele, dynamická alokace

IUJCE 07/08 Přednáška č. 6

Správa paměti. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta, 2016

Více o konstruktorech a destruktorech

PB161 Programování v jazyce C++ Přednáška 11

PB161 Programování v jazyce C++ Přednáška 2

PB161 Programování v jazyce C++ Přednáška 11

Generické programování

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

Mělká a hluboká kopie

Dynamika objektů. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze

Programování v C++ 2, 4. cvičení

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

Hrátky s funkcemi. PV173 Programování v C++11. Vladimír Štill, Jiří Weiser. Fakulta Informatiky, Masarykova Univerzita. 29.

Správa paměti. doc. Ing. Miroslav Beneš, Ph.D. katedra informatiky FEI VŠB-TUO A-1007 /

PB přednáška (23. listopadu 2015)

Základy programování (IZP)

IB111 Úvod do programování skrze Python Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

PB161 Programování v jazyce C++ Přednáška 7

Programování v jazyce C a C++

Struktura programu v době běhu

Základy programování (IZP)

Dědění, polymorfismus

Ukazatele #2, dynamická alokace paměti

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PB161 Programování v jazyce C++ Přednáška 2

Úvod. Karel Richta a kol. katedra počítačů FEL ČVUT v Praze. Karel Richta, Martin Hořeňovský, Aleš Hrabalík,2016

PB071 Programování v jazyce C Jaro 2015

konstruktory a destruktory (o)

Konstruktory a destruktory

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Vláknové programování část V

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Jazyk C# (seminář 6)

Práce s polem a pamětí

Ukazatel (Pointer) jako datový typ - proměnné jsou umístěny v paměti na určitém místě (adrese) a zabírají určitý prostor (počet bytů), který je daný

PREPROCESOR POKRAČOVÁNÍ

Programování v C++ 3, 3. cvičení

PB161 Programování v jazyce C++ Přednáška 10

Úvod Třídy Rozhraní Pole Konec. Programování v C# Hodnotové datové typy, řídící struktury. Petr Vaněček 1 / 39

8 Třídy, objekty, metody, předávání argumentů metod

Matematika v programovacích

PB071 Programování v jazyce C Jaro 2017

PŘETĚŽOVÁNÍ OPERÁTORŮ

Programování v C++, 2. cvičení

Tabulka symbolů. Vazba (binding) Vazba - příklad. Deklarace a definice. Miroslav Beneš Dušan Kolář

Dynamická alokace paměti

Principy objektově orientovaného programování

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Programování v C++ 1, 17. cvičení

Spojová implementace lineárních datových struktur

Programování v C++ VI

Abstraktní datové typy

Programování v C++ 1, 5. cvičení

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Dědičnost (inheritance)

Singleton obsah. Motivace Základní myšlenka Implementace Problémy. Dědičnost Obecná implementace Shrnutí. destrukce vícevláknovost

Programování v jazyce C a C++

Datové typy v Javě. Tomáš Pitner, upravil Marek Šabo

MATURITNÍ OTÁZKY ELEKTROTECHNIKA - POČÍTAČOVÉ SYSTÉMY 2003/2004 PROGRAMOVÉ VYBAVENÍ POČÍTAČŮ

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

PB071 Principy nízkoúrovňového programování

Z. Kotala, P. Toman: Java ( Obsah )

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

Přetěžování operátorů, dynamika objektů 2

C++ přetěžování funkcí a operátorů. Jan Hnilica Počítačové modelování 19

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

Ukazka knihy z internetoveho knihkupectvi

Základy programování 2 KMI/ZP2

Programování v C++ 2, 8. cvičení

Funkční objekty v C++.

PROGRAMOVÁNÍ V C++ CVIČENÍ. Michal Brabec

int ii char [16] double dd název adresa / proměnná N = nevyužito xxx xxx xxx N xxx xxx N xxx N

Programování II. Návrh programu I 2018/19

IRAE 07/08 Přednáška č. 2. atr1 atr2. atr1 atr2 -33

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Bridge. Známý jako. Účel. Použitelnost. Handle/Body

Definice třídy. úplná definice. public veřejná třída abstract nesmí být vytvářeny instance final nelze vytvářet potomky

NMIN102 Programování /2 Z, Zk

Pokročilé programování v jazyce C pro chemiky (C3220) Statické proměnné a metody, šablony v C++

Distanční opora předmětu: Programování v jazyce C Tématický blok č. 6: Dynamická alokace paměti, typové konstrukce Autor: RNDr. Jan Lánský, Ph.D.

Programování v C++ 2, 7. cvičení

Objektově orientované programování

Základy C++ I. Jan Hnilica Počítačové modelování 18

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

4. ZÁKLADNÍ POJMY Z OBJEKTOVĚ ORIENTOVANÉHO PROGRAMOVÁNÍ

Správné vytvoření a otevření textového souboru pro čtení a zápis představuje

PB161 Programování v jazyce C++ Přednáška 1

PB161 programování v C++ Výjimky Bezpečné programování

Transkript:

PB161 Programování v jazyce C++ Přednáška 5 Práce s pamětí Princip RAII Lehký úvod do výjimek Nikola Beneš 16. října 2018 PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 1 / 28

Přetypování (cast) Co už jste (možná) pochopili (-Wold-style-cast) v moderním C++ nechceme používat Céčkové přetypování (typ)hodnota divná syntax, nejasná priorita; není typově bezpečné Jaké máme možnosti v C++? static_cast<typ>(hodnota) základní přetypování; většinou bezpečné const_cast<typ>(hodnota) umožňuje porušit const jen pokud skutečně víte, co děláte; pozor na nedefinované chování reinterpret_cast<typ>(hodnota) donutí kompilátor dívat se na kus paměti jako na jiný typ to velmi často není to, co chcete má občas použití v nízkoúrovňovém kódu (práce s binárními soubory) dynamic_cast<typ>(hodnota) použití při dědičnosti; uvidíme později PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 2 / 28

Přetypování (cast) Co už jste (možná) pochopili (-Wold-style-cast) v moderním C++ nechceme používat Céčkové přetypování (typ)hodnota divná syntax, nejasná priorita; není typově bezpečné Jaké máme možnosti v C++? Nepoužívejte, pokud vám to explicitně nepovolíme static_cast<typ>(hodnota) základní přetypování; většinou bezpečné const_cast<typ>(hodnota) umožňuje porušit const jen pokud skutečně víte, co děláte; pozor na nedefinované chování reinterpret_cast<typ>(hodnota) donutí kompilátor dívat se na kus paměti jako na jiný typ to velmi často není to, co chcete má občas použití v nízkoúrovňovém kódu (práce s binárními soubory) dynamic_cast<typ>(hodnota) použití při dědičnosti; uvidíme později PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 2 / 28

Práce s pamětí PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 3 / 28

Připomenutí Ukazatel proměnná, která drží adresu v paměti aritmetika ukazatelů (přičtení čísla k ukazateli, rozdíl ukazatelů) rozdíl mezi const int* a int* const a případně const int* const speciální ukazatel nullptr (od C++11) dříve NULL nepoužívat v novém kódu! PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 4 / 28

Alokace paměti znáte z C Alokace na zásobníku (stack) lokální proměnné; automatické uvolnění paměti na konci bloku (v C++ navíc automatické volání destruktorů) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 5 / 28

Alokace paměti znáte z C Alokace na zásobníku (stack) lokální proměnné; automatické uvolnění paměti na konci bloku (v C++ navíc automatické volání destruktorů) Statická alokace globální proměnné, statické proměnné ve funkcích (v C++ navíc statické atributy uvidíme později) alokace před spuštěním programu inicializace před začátkem funkce main (složitější) dealokace po skončení programu (v C++ navíc volání destruktorů) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 5 / 28

Alokace paměti znáte z C Alokace na zásobníku (stack) lokální proměnné; automatické uvolnění paměti na konci bloku (v C++ navíc automatické volání destruktorů) Statická alokace globální proměnné, statické proměnné ve funkcích (v C++ navíc statické atributy uvidíme později) alokace před spuštěním programu inicializace před začátkem funkce main (složitější) dealokace po skončení programu (v C++ navíc volání destruktorů) Dynamická alokace na haldě (heap) explicitní žádost o paměť explicitní uvolnění paměti znáte z C: malloc/free (v C++ nepoužíváme) nebezpečné: žádná typová kontrola, bez inicializace PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 5 / 28

Práce s pamětí v C++ Nízkoúrovňová (ruční) operátory new a delete new alokuje paměť na haldě a zavolá konstruktor delete zavolá destruktor a dealokuje paměť moderní C++: příliš nepoužívat, jen v nutných případech nicméně je dobré vědět, jak funguje PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 6 / 28

Práce s pamětí v C++ Nízkoúrovňová (ruční) operátory new a delete new alokuje paměť na haldě a zavolá konstruktor delete zavolá destruktor a dealokuje paměť moderní C++: příliš nepoužívat, jen v nutných případech nicméně je dobré vědět, jak funguje Vysokoúrovňová (automatická) využití standardní knihovny, příp. jiných knihoven (boost apod.) už jsme vlastně viděli vector, string a jiné kontejnery vnitřně alokují a dealokují paměť na haldě jiné možnosti: chytré ukazatele automatické uvolnění paměti unique_ptr (od C++11 ve standardní knihovně) a jiné PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 6 / 28

Nízkoúrovňová správa paměti Dva způsoby alokace jeden objekt pole objektů int* ptr = new int; int* array = new int[20]; když se alokace nezdaří, vyhodí výjimku (o těch bude řeč později) není proto třeba kontrolovat na nullptr PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 7 / 28

Nízkoúrovňová správa paměti Dva způsoby alokace jeden objekt pole objektů int* ptr = new int; int* array = new int[20]; když se alokace nezdaří, vyhodí výjimku (o těch bude řeč později) není proto třeba kontrolovat na nullptr Odpovídající způsoby dealokace delete ptr; delete [] array; musí odpovídat použitému new nehlídá kompilátor (někdy ovšem umí dát warning)! Proč? lecture05_01.cpp, lecture05_02.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 7 / 28

Nízkoúrovňová správa paměti (pokr.) Inicializace alokovaných objektů funguje podobně jako inicializace lokálních objektů int* ptr1 = new int; // neinicializovaná paměť int* ptr2 = new int(17); // paměť inicializovaná na 17 int* ptr3 = new int(); // paměť inicializovaná na 0 PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 8 / 28

Nízkoúrovňová správa paměti (pokr.) Inicializace alokovaných objektů funguje podobně jako inicializace lokálních objektů int* ptr1 = new int; // neinicializovaná paměť int* ptr2 = new int(17); // paměť inicializovaná na 17 int* ptr3 = new int(); // paměť inicializovaná na 0 Obj* ptr4 = new Obj; // zavolá se konstruktor Obj::Obj() Obj* ptr5 = new Obj(3, 5); // konstruktor Obj::Obj(int, int) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 8 / 28

Nízkoúrovňová správa paměti (pokr.) Inicializace alokovaných objektů funguje podobně jako inicializace lokálních objektů int* ptr1 = new int; // neinicializovaná paměť int* ptr2 = new int(17); // paměť inicializovaná na 17 int* ptr3 = new int(); // paměť inicializovaná na 0 Obj* ptr4 = new Obj; // zavolá se konstruktor Obj::Obj() Obj* ptr5 = new Obj(3, 5); // konstruktor Obj::Obj(int, int) Alokace a inicializace polí int* arr1 = new int[200]; // neinicializovaná paměť int* arr2 = new int[200](); // paměť inicializovaná na 0 lecture05_03.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 8 / 28

Nízkoúrovňová správa paměti (pokr.) Inicializace alokovaných objektů funguje podobně jako inicializace lokálních objektů int* ptr1 = new int; // neinicializovaná paměť int* ptr2 = new int(17); // paměť inicializovaná na 17 int* ptr3 = new int(); // paměť inicializovaná na 0 Obj* ptr4 = new Obj; // zavolá se konstruktor Obj::Obj() Obj* ptr5 = new Obj(3, 5); // konstruktor Obj::Obj(int, int) Alokace a inicializace polí int* arr1 = new int[200]; // neinicializovaná paměť int* arr2 = new int[200](); // paměť inicializovaná na 0 Obj* arr3 = new Obj[200]; // zavolá se konstruktor Obj::Obj() samozřejmě funguje i inicializace pomocí {} lecture05_03.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 8 / 28

Nízkoúrovňová správa paměti (pokr.) Problémy správy paměti (některé znáte z C) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 9 / 28

Nízkoúrovňová správa paměti (pokr.) Problémy správy paměti (některé znáte z C) memory leak (alokovaná paměť, na kterou již nemáme ukazatel) zápis do/čtení z nealokované paměti čtení z neinicializované paměti volání delete na špatný ukazatel volání delete místo delete [] a naopak volání free na paměť alokovanou new, nebo delete/delete[] na pamět alokovanou malloc PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 9 / 28

Nízkoúrovňová správa paměti (pokr.) Problémy správy paměti (některé znáte z C) memory leak (alokovaná paměť, na kterou již nemáme ukazatel) zápis do/čtení z nealokované paměti čtení z neinicializované paměti volání delete na špatný ukazatel volání delete místo delete [] a naopak volání free na paměť alokovanou new, nebo delete/delete[] na pamět alokovanou malloc v C++ nikdy nepoužíváme free/malloc (leda by to vyžadovala použitá C knihovna)! PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 9 / 28

Nízkoúrovňová správa paměti (pokr.) Problémy správy paměti (některé znáte z C) memory leak (alokovaná paměť, na kterou již nemáme ukazatel) zápis do/čtení z nealokované paměti čtení z neinicializované paměti volání delete na špatný ukazatel volání delete místo delete [] a naopak volání free na paměť alokovanou new, nebo delete/delete[] na pamět alokovanou malloc v C++ nikdy nepoužíváme free/malloc (leda by to vyžadovala použitá C knihovna)! Motivace pro chytré ukazatele chceme ukazatel, který sám provede delete, když je potřeba PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 9 / 28

Vysokoúrovňová správa paměti Chytré ukazatele několik druhů ve standardní knihovně (od C++11), příp. v jiných knihovnách (boost) v tomto předmětu si ukážeme pouze jeden PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 10 / 28

Vysokoúrovňová správa paměti Chytré ukazatele několik druhů ve standardní knihovně (od C++11), příp. v jiných knihovnách (boost) v tomto předmětu si ukážeme pouze jeden std::unique_ptr nejjednodušší, ale pokrývá většinu potřeb má nulovou režii (overhead) za běhu, na rozdíl od jiných použitelný pro jednotlivé objekty i pole PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 10 / 28

Vysokoúrovňová správa paměti Chytré ukazatele několik druhů ve standardní knihovně (od C++11), příp. v jiných knihovnách (boost) v tomto předmětu si ukážeme pouze jeden std::unique_ptr nejjednodušší, ale pokrývá většinu potřeb má nulovou režii (overhead) za běhu, na rozdíl od jiných použitelný pro jednotlivé objekty i pole základní princip: objekt, který uvnitř drží ukazatel (koncept vlastnictví) na konci života objektu se zavolá delete na vlastněný ukazatel (tedy zavolá destruktor a dealokuje) vlastnictví se nedá sdílet (proto unique) ale může se explicitně předat PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 10 / 28

Vysokoúrovňová správa paměti (pokr.) Základní použití std::unique_ptr alokace pokud neinicializujeme, je automaticky nullptr std::unique_ptr<object> ptr(new Object(params)); // v C++11 // od C++14 používejte raději takto auto ptr = std::make_unique<object>(params); lecture05_04.cpp, lecture05_05.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 11 / 28

Vysokoúrovňová správa paměti (pokr.) Základní použití std::unique_ptr alokace pokud neinicializujeme, je automaticky nullptr std::unique_ptr<object> ptr(new Object(params)); // v C++11 // od C++14 používejte raději takto auto ptr = std::make_unique<object>(params); přístup k objektu stejně jak u klasických ukazatelů (*, ->) pozor, nedefinované chování, pokud by byl ptr == nullptr ptr->method(); function(*ptr); lecture05_04.cpp, lecture05_05.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 11 / 28

Vysokoúrovňová správa paměti (pokr.) Základní použití std::unique_ptr alokace pokud neinicializujeme, je automaticky nullptr std::unique_ptr<object> ptr(new Object(params)); // v C++11 // od C++14 používejte raději takto auto ptr = std::make_unique<object>(params); přístup k objektu stejně jak u klasických ukazatelů (*, ->) pozor, nedefinované chování, pokud by byl ptr == nullptr ptr->method(); function(*ptr); dealokace, zavolání destruktoru objektu lokální unique_ptr: automaticky, na konci bloku unique_ptr jako atribut: automaticky po destruktoru hlavního objektu explicitně: zavoláním metody reset() lecture05_04.cpp, lecture05_05.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 11 / 28

Vysokoúrovňová správa paměti (pokr.) zjištění, zda unique_ptr obsahuje nějaký ukazatel if (ptr) {... } lecture05_06.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 12 / 28

Vysokoúrovňová správa paměti (pokr.) zjištění, zda unique_ptr obsahuje nějaký ukazatel if (ptr) {... } přímý přístup ke spravovanému ukazateli (k čemu je to dobré?) Object* rawptr = ptr.get(); // ptr je stále vlastníkem ukazatele lecture05_06.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 12 / 28

Vysokoúrovňová správa paměti (pokr.) zjištění, zda unique_ptr obsahuje nějaký ukazatel if (ptr) {... } přímý přístup ke spravovanému ukazateli (k čemu je to dobré?) Object* rawptr = ptr.get(); // ptr je stále vlastníkem ukazatele vzdání se vlastnictví (k čemu je to dobré?) // tohle raději nedělejte! Object* rawptr = ptr.release(); // ptr už není vlastníkem ukazatele, který je nyní uložen // v rawptr, a je třeba jej uvolnit ručně! lecture05_06.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 12 / 28

Vysokoúrovňová správa paměti (pokr.) předávání vlastnictví jinému unique_ptr unique_ptr se nedá kopírovat! // tohle nebude fungovat std::unique_ptr<object> newptr = ptr; // chyba! PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 13 / 28

Vysokoúrovňová správa paměti (pokr.) předávání vlastnictví jinému unique_ptr unique_ptr se nedá kopírovat! // tohle nebude fungovat std::unique_ptr<object> newptr = ptr; // chyba! unique_ptr se umí tzv. přesouvat (move) využívá rvalue semantics, mimo záběr předmětu std::unique_ptr<object> newptr = std::move(ptr); // newptr teď vlastní ukazatel, který předtím vlastnil ptr // ptr teď nevlastní nic, je tedy ekvivalentní nullptr PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 13 / 28

Vysokoúrovňová správa paměti (pokr.) předávání vlastnictví jinému unique_ptr unique_ptr se nedá kopírovat! // tohle nebude fungovat std::unique_ptr<object> newptr = ptr; // chyba! unique_ptr se umí tzv. přesouvat (move) využívá rvalue semantics, mimo záběr předmětu std::unique_ptr<object> newptr = std::move(ptr); // newptr teď vlastní ukazatel, který předtím vlastnil ptr // ptr teď nevlastní nic, je tedy ekvivalentní nullptr funguje nejen při inicializaci, ale i při přiřazení auto ptra = std::make_unique<object>(); auto ptrb = std::make_unique<object>(); ptra = std::move(ptrb); // kdo co vlastní teď? lecture05_07.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 13 / 28

Vysokoúrovňová správa paměti (pokr.) použití pro alokaci polí // v C++11 std::unique_ptr<object[]> ptr(new Object[size]); // od C++14 používejte raději takto auto ptr = std::make_unique<object[]>(size); // alokuje paměť pro size objektů // a všechny inicializuje bezparametrickým konstruktorem PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 14 / 28

Vysokoúrovňová správa paměti (pokr.) použití pro alokaci polí // v C++11 std::unique_ptr<object[]> ptr(new Object[size]); // od C++14 používejte raději takto auto ptr = std::make_unique<object[]>(size); // alokuje paměť pro size objektů // a všechny inicializuje bezparametrickým konstruktorem použití pro alokací polí primitivních typů auto ptr = std::make_unique<int[]>(size); // alokuje paměť pro size intů // a všechny inicializuje na 0 inicializuje tedy jako new int[size]() lecture05_08.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 14 / 28

Vysokoúrovňová správa paměti (pokr.) Jak správně pracovat s ukazateli v moderním C++ jasně si rozmyslete, kdo bude vlastníkem ukazatele ten pak má unique_ptr ukazující na daný objekt ostatní (ne-vlastníci) smí mít klasický (surový, raw) ukazatel na tentýž objekt (nebo lépe referenci) je třeba zaručit, aby vlastník ukazatele přežil všechny ne-vlastníky, kteří ukazovaný objekt používají Jak předávat unique_ptr do funkce? lecture05_09.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 15 / 28

Vysokoúrovňová správa paměti (pokr.) Jak správně pracovat s ukazateli v moderním C++ jasně si rozmyslete, kdo bude vlastníkem ukazatele ten pak má unique_ptr ukazující na daný objekt ostatní (ne-vlastníci) smí mít klasický (surový, raw) ukazatel na tentýž objekt (nebo lépe referenci) je třeba zaručit, aby vlastník ukazatele přežil všechny ne-vlastníky, kteří ukazovaný objekt používají Jak předávat unique_ptr do funkce? hodnotou typu unique_ptr: volající pak musí použít std::move a tím se vzdává vlastnictví ukazatele referencí: volaná funkce může sebrat vlastnictví (nedoporučované) const referencí: v podstatě OK, ale volaná funkce může modifikovat odkazovaný objekt (je to jakoby Object* const) surový ukazatel: může být Object * nebo const Object * úplně nejlépe referencí na Object: lecture05_09.cpp volající musí zajistit, že není nullptr PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 15 / 28

Vysokoúrovňová správa paměti (pokr.) Datové struktury a unique_ptr je třeba rozmyslet strukturu vlastnictví lecture05_10.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 16 / 28

Vysokoúrovňová správa paměti (pokr.) Datové struktury a unique_ptr je třeba rozmyslet strukturu vlastnictví není možné mít ve vlastnictví cykly (proč?) lecture05_10.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 16 / 28

Vysokoúrovňová správa paměti (pokr.) Datové struktury a unique_ptr je třeba rozmyslet strukturu vlastnictví není možné mít ve vlastnictví cykly (proč?) není možné, aby dva vlastnili stejný objekt lecture05_10.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 16 / 28

Vysokoúrovňová správa paměti (pokr.) Datové struktury a unique_ptr je třeba rozmyslet strukturu vlastnictví není možné mít ve vlastnictví cykly (proč?) není možné, aby dva vlastnili stejný objekt oboustranně zřetězený seznam (v prvcích) next je unique_ptr, prev je ukazatel (v seznamu) first je unique_ptr, last je ukazatel nebo naopak lecture05_10.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 16 / 28

Vysokoúrovňová správa paměti (pokr.) Datové struktury a unique_ptr je třeba rozmyslet strukturu vlastnictví není možné mít ve vlastnictví cykly (proč?) není možné, aby dva vlastnili stejný objekt oboustranně zřetězený seznam (v prvcích) next je unique_ptr, prev je ukazatel (v seznamu) first je unique_ptr, last je ukazatel nebo naopak binární strom vztah rodič vlastní potomky left a right jsou unique_ptr, případný parent je ukazatel apod. lecture05_10.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 16 / 28

Správa paměti v moderním C++ Doporučení používejte vysokoúrovňovou správu paměti (unique_ptr) nepoužívejte new a delete ale naučte se jim rozumět často je uvidíte v cizím kódu do funkcí předávejte objekty pokud možno referencí (toto doporučení už bylo!) předávejte unique_ptr hodnotou, pokud se chcete vzdát vlastnictví implementujete-li složitější datovou strukturu s ukazateli, rozmyslete si strukturu vlastnictví (kdo koho vlastní) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 17 / 28

Správa zdrojů princip RAII ACQUIRE USE RELEASE PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 18 / 28

Správa zdrojů Co to je zdroj? PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 19 / 28

Správa zdrojů Co to je zdroj? něco, co se získá (acquire) potom se to používá (use) nakonec se to uvolní (release) Příklady zdrojů PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 19 / 28

Správa zdrojů Co to je zdroj? něco, co se získá (acquire) potom se to používá (use) nakonec se to uvolní (release) Příklady zdrojů paměť na haldě PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 19 / 28

Správa zdrojů Co to je zdroj? něco, co se získá (acquire) potom se to používá (use) nakonec se to uvolní (release) Příklady zdrojů paměť na haldě soubory síťová připojení zámky, mutexy, semafory, apod. PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 19 / 28

Správa zdrojů Co to je zdroj? něco, co se získá (acquire) potom se to používá (use) nakonec se to uvolní (release) Příklady zdrojů paměť na haldě soubory síťová připojení zámky, mutexy, semafory, apod. v C++ vše funguje na stejném principu Různé jazyky často implementují automatickou správu paměti, ale ne automatickou správu zdrojů (v posledních letech se to trochu zlepšuje). C++ má automatickou správu zdrojů už skoro od svého počátku. PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 19 / 28

Správa zdrojů v C++ Princip RAII Resource Acquisition Is Initialisation někdy též zváno scope-based resource management správa zdroje spjatá s životním cyklem objektu inicializace objektu: získání zdroje (acquire) destruktor: uvolnění zdroje (release) ideálně: jeden objekt spravuje jeden zdroj PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 20 / 28

Správa zdrojů v C++ Princip RAII Resource Acquisition Is Initialisation někdy též zváno scope-based resource management správa zdroje spjatá s životním cyklem objektu inicializace objektu: získání zdroje (acquire) destruktor: uvolnění zdroje (release) ideálně: jeden objekt spravuje jeden zdroj Kde se používá RAII? skoro všude! string, vector, všechny kontejnery práce se soubory v C++ (později) chytré ukazatele: unique_ptr (C++11) zamykání, mutexy (C++11, nad rámec kurzu) PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 20 / 28

Princip RAII Příklad dynamické pole intů (pamatujete na Rule of Three?) class IntArray { size_t size; int* array; public: IntArray(size_t size) : size(size), array(new int[size]) {} ~IntArray() { delete [] array; } IntArray(const IntArray& other) : size(other.size), array(new int[size]) { std::copy(other.array, other.array + size, array); } IntArray& operator=(const IntArray& other) { // viz další slajdy } } lecture05_11.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 21 / 28

Příklad dynamické pole intů Jak implementovat přiřazovací operátor? IntArray& operator=(const IntArray& other) { delete [] array; size = other.size; array = new int[size]; std::copy(other.array, other.array + size, array); return *this; } kde je problém? PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 22 / 28

Příklad dynamické pole intů Jak implementovat přiřazovací operátor? IntArray& operator=(const IntArray& other) { delete [] array; size = other.size; array = new int[size]; std::copy(other.array, other.array + size, array); return *this; } kde je problém? sebe-přiřazení (co se stane, když napíšu x = x;?) jak řešit? PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 22 / 28

Příklad dynamické pole intů (pokr.) Kontrola sebe-přiřazení IntArray& operator=(const IntArray& other) { if (&other == this) return *this; delete [] array; size = other.size; array = new int[size]; std::copy(other.array, other.array + size, array); return *this; } optimalizace není třeba dělat delete [] a new [], pokud jsou velikosti stejné PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 23 / 28

Příklad dynamické pole intů (pokr.) Jiná možnost, tzv. copy-and-swap idiom void swap(intarray& other) { using std::swap; swap(size, other.size); swap(array, other.array); } IntArray& operator=(intarray other) { // HODNOTOU! swap(other); return *this; } co se děje? PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 24 / 28

ke třem dříve zmíněným se přidá metoda swap copy-and-swap idiom silně doporučujeme! PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 24 / 28 Příklad dynamické pole intů (pokr.) Jiná možnost, tzv. copy-and-swap idiom void swap(intarray& other) { using std::swap; swap(size, other.size); swap(array, other.array); } IntArray& operator=(intarray other) { // HODNOTOU! swap(other); return *this; } co se děje? Rule of Three and a Half

Princip RAII Jiné příklady (pro ilustraci) třída File konstruktor otevře soubor destruktor zavře soubor kopírování nejspíše zakážeme PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 25 / 28

Princip RAII Jiné příklady (pro ilustraci) třída File konstruktor otevře soubor destruktor zavře soubor kopírování nejspíše zakážeme třída Mutex konstruktor zamkne mutex destruktor odemkne mutex kopírování opět zakážeme PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 25 / 28

Princip RAII Jiné příklady (pro ilustraci) třída File konstruktor otevře soubor destruktor zavře soubor kopírování nejspíše zakážeme třída Mutex konstruktor zamkne mutex destruktor odemkne mutex kopírování opět zakážeme třída Texture konstruktor načte texturu ze souboru do paměti GPU destruktor uvolní paměť GPU kopírování: vytvoření nové textury PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 25 / 28

Princip RAII v jiných jazycích Některé jazyky mají RAII C++, D, Ada, Rust umí plné RAII tak trochu: Perl, Python (CPython), PHP mají reference counting Správa zdrojů v jiných jazycích garbage collector: správa paměti, typicky neumožňuje správu zdrojů (není žádná záruka, kdy a jestli vůbec se zavolají destruktory) Java (od 1.7) synchronized try(resource res = new Resource(...)) {... } Python (od 2.5) with get_resource() as resource: C# using(resource res = new Resource(...)) {... } PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 26 / 28

Lehký úvod do výjimek Výjimky způsob, jak řešit výjimečné situace (chyby) za běhu programu vyhození výjimky: throw zachycení výjimky: try {... } catch(...) {... } standardní výjimky v knihovně: <stdexcept> testování v Catch2: REQUIRE_THROWS_AS(výraz, typ výjimky) apod. int main() { try { throw std::runtime_error("something bad happened."); } catch (std::runtime_error& ex) { std::cout << ex.what() << '\n'; } } lecture05_12.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 27 / 28

Lehký úvod do výjimek (pokr.) Pár pravidel (podrobněji se k nim dostaneme později) výjimkami řešte pouze výjimečné situace házejte hodnotou, chytejte referencí nevyhazujte výjimky z destruktorů vyhazujte výjimky z konstruktorů, pokud nedokážete smysluplně dokončit konstrukci objektu PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 28 / 28

Lehký úvod do výjimek (pokr.) Pár pravidel (podrobněji se k nim dostaneme později) výjimkami řešte pouze výjimečné situace házejte hodnotou, chytejte referencí nevyhazujte výjimky z destruktorů vyhazujte výjimky z konstruktorů, pokud nedokážete smysluplně dokončit konstrukci objektu Vztah výjimek a RAII destrukory lokálních objektů se zavolají vždy při opuštění bloku to se týká i opuštění bloku při vyhození výjimky srovnejte použití std::unique_ptr a explicitního new a delete ve chvíli, kdy uvnitř bloku vznikne výjimka lecture05_13.cpp PB161 přednáška 5: práce s pamětí, princip RAII, lehce výjimky 16. října 2018 28 / 28