A C++11 újdonságai. Smidla József Operációkutatási Laboratórium 2014. október 9.

Hasonló dokumentumok
3. Osztályok II. Programozás II

Programozás II gyakorlat. 8. Operátor túlterhelés

Programozás II. 4. Dr. Iványi Péter

1. Alapok. Programozás II

Bevezetés a programozásba Előadás: Tagfüggvények, osztály, objektum

Bevezetés a programozásba 2

C++ programozási nyelv Konstruktorok-destruktorok

C++ Standard Template Library (STL)

500. AA Megoldó Alfréd AA 500.

Objektumok inicializálása

Programozás II. 2. Dr. Iványi Péter

Bevezetés a Programozásba II 11. előadás. Adatszerkezetek megvalósítása. Adatszerkezetek megvalósítása Adatszerkezetek

OOP #14 (referencia-elv)

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

Pénzügyi algoritmusok

Osztály és objektum fogalma

5. Gyakorlat. struct diak {

Programozás C++ -ban

Programozás C++ -ban 2007/7

Osztályok. 4. gyakorlat

Programozás C és C++ -ban

A C programozási nyelv V. Struktúra Dinamikus memóriakezelés

Programozás II. 3. gyakorlat Objektum Orientáltság C++-ban

STL gyakorlat C++ Izsó Tamás május 9. Izsó Tamás STL gyakorlat/ 1

Programozás C++ -ban 2007/4

Pelda öröklődésre: import java.io.*; import java.text.*; import java.util.*; import extra.*;

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok

Visual C++ osztály készítése, adattagok, és metódusok, láthatóság, konstruktor, destruktor. Objektum létrehozása, használata, öröklés.

Programozási Nyelvek: C++

- 1 - Konstansok használata. Döntsük el, van-e fordítási idejű hiba az alábbi programrészletekben! a) const char * str="zh"; str[0]++;

Bevezetés a programozásba Előadás: A const

Dinamikus csatolású függvénykönyvtár készítése és használata Plugin-szerű betöltés Egyszeű C++ osztályok készítése

Programozás módszertan

Az alábbi példában a Foo f(5); konstruktor hívása után mennyi lesz f.b értéke? struct Foo { int a, b; Foo(int c):a(c*2),b(c*3) {} };

Programozás II gyakorlat. 6. Polimorfizmus

C++ programozási nyelv

Programozás C++ -ban

0. Megoldó Manó 0. Programozás alapjai 2. (inf.) pót zárthelyi gyak. hiányzás: 2 n/kzhp: n/11,5. ABCDEF IB.028/2.

PROGRAMOZÁSI NYELVEK - CPP. GYAKORLAT JEGYZET

Bevezetés a programozásba I.

Alkalmazott modul: Programozás 8. előadás. Strukturált programozás: dinamikus memóriakezelés. Dinamikus memóriakezelés. Dinamikus memóriakezelés

8. gyakorlat Pointerek, dinamikus memóriakezelés

Programozás alapjai II. (4. ea) C++

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra

Járműfedélzeti rendszerek II. 3. előadás Dr. Bécsi Tamás

Fejlett programozási nyelvek C++ Iterátorok

Statikus adattagok. Statikus adattag inicializálása. Speciális adattagok és tagfüggvények. Általános Informatikai Tanszék

Programozás alapjai II. (9. ea) C++ többszörös öröklés, cast, perzisztencia

4. Öröklődés. Programozás II

Bevezetés a programozásba. 8. Előadás: Függvények 2.

Miután létrehoztuk, szeretnénk neki beszédesebb nevet adni. A név változtatásához a következőt kell tenni:

Java és web programozás

Bevezetés a programozásba. 9. Előadás: Rekordok

C# osztálydeníció. Krizsán Zoltán 1. .net C# technológiák tananyag objektum orientált programozás tananyag

C++ Gyakorlat jegyzet 7. óra

C++ Gyakorlat jegyzet 5. óra. A C++ szabvány több memóriatípust különít el. Ezek közül elsősorban a stack-et használtuk eddig.

500. CC Megoldó Alfréd CC 500.

503.AA Megoldo Arisztid 503.A

STL. Algoritmus. Iterátor. Tároló. Elsődleges komponensek: Tárolók Algoritmusok Bejárók

Bevezetés a programozásba Előadás: Objektumszintű és osztályszintű elemek, hibakezelés

Alkalmazott modul: Programozás 9. előadás. Strukturált programozás: dinamikus adatszerkezetek

C programozási nyelv Pointerek, tömbök, pointer aritmetika

Szövegek C++ -ban, a string osztály

C++ programozási nyelv Struktúrák a C++ nyelvben

Kivételek, kivételkezelés a C++ nyelvben

Java V. Osztályszint. lyszintű ű tagok. Példányváltozó. Osztályváltozó. Általános Informatikai Tanszék Utolsó módosítás:

Programozás I gyakorlat

Memóriakezelés, dinamikus memóriakezelés

0.2.1 Operátorok túlterhelése (műveletek definiálhatók felhaszn. típusokra) Kutya. Eb1. Eb2. Név (txt): Rex. Blöki. Német juhász 3

A lista eleme. mutató rész. adat rész. Listaelem létrehozása. Node Deklarálás. Létrehozás. Az elemet nekünk kell bef zni a listába

C++ Gyakorlat jegyzet 8. óra

Alprogramok, paraméterátadás

128. AA Megoldó Alfréd AA 128.

Alkalmazott modul: Programozás 10. fejezet. Strukturált programozás: dinamikus memóriakezelés. Giachetta Roberto

Java II. I A Java programozási nyelv alapelemei

C++ Gyakorlat jegyzet 5. óra. A C++ szabvány több memóriatípust különít el. Ezek közül elsősorban a stack-et használtuk eddig.

C# nyelv alapjai. Krizsán Zoltán 1. Objektumorientált programozás C# alapokon tananyag. Általános Informatikai Tanszék Miskolci Egyetem

Pénzügyi algoritmusok

Apple Swift kurzus 3. gyakorlat

Java és web programozás

Java III. I I. Osztálydefiníció (Bevezetés)

Programozás II gyakorlat. 7. Példák a polimorfizmus alkalmazásaira

Programozás C- és Matlab nyelven C programozás kurzus BMEKOKAM603 Mutatók. Dr. Bécsi Tamás 7. Előadás

Bánsághi Anna 2014 Bánsághi Anna 1 of 33

Java III. I I. Osztálydefiníció (Bevezetés)

Bevezetés, a C++ osztályok. Pere László

Java programozási nyelv 4. rész Osztályok II.

és az instanceof operátor

Bevezetés a C++ programozási nyelvbe

Java VIII. Az interfacei. és az instanceof operátor. Az interfészről általában. Interfészek JAVA-ban. Krizsán Zoltán

500.AA Megoldó Kulcsár 500.A

1) Hány byte-on tárol a C++ egy karaktert (char)? implementáció-függő ( viszont lásd 79. megjegyzés ) 1 8 4

Pénzügyi algoritmusok

117. AA Megoldó Alfréd AA 117.

Programozás. Osztályok, Származtatott osztályok. Fodor Attila

A feladat lényege egy felhasználói típusnak a zsák típusnak a megvalósítása.

OOP: Java 11.Gy: Enumok, beágyazott osztályok. 13/1 B ITv: MAN

228. AA Default Konstruktor AA 228.

Generikus Típusok, Kollekciók

Cekla. Készítette Doxygen Tue Sep :13:44

Átírás:

A C++11 újdonságai Smidla József Operációkutatási Laboratórium 2014. október 9. 1

Tartalom nyers string auto, decltype nullptr constexpr foreach újdonságok osztályokban típusos enum lambda kifejezések struktúra inicializálás inicializáló lista smart pointerek szálkezelés 2

A C++11 szabvány A szabvány 2011 szeptemberében jelent meg Ha a gcc-t használjuk, akkor érdemes legalább a 4.8.1-s verziót használni A gcc alapesetben még a 2003-as szabványt támogatja Adjuk meg a fordítónak a std=c++11 kapcsolót! A nyelv azóta is fejlődik, a legújabb szabvány a 2014-es Jelen előadásnak nem célja, hogy teljes áttekintést nyújtson a C++11-ről 3

Nyers stringek Hagyományos stringek: cout << "Hello World";! HIBA Nyers stringek: cout << R"(Hello World \n \n \t!)"; 4

Nyers stringek Hagyományos stringek: cout << "Hello World";! HIBA Nyers stringek: cout << R"(Hello World \n \n \t!)"; Nyers string Határoló karaktersorozatok 5

Nyers stringek A nyers stringek úgy tárolódnak, ahogy azokat beírtuk a forráskódba: Összetettebb határoló karaktersorozat: cout << R"valami(pelda: R"(alma)" )valami"; A és a zárójelek közé tetszőleges határoló karaktersorozatot írhatunk 6

auto, decltype Adott egy összetett tároló: std::map<int, std::vector<string> > m; 7

auto, decltype Adott egy összetett tároló: std::map<int, std::vector<string> > m; Járjuk végig egy iterátorral: std::map<int, std::vector<string> >::iterator iter = m.begin(); 8

auto, decltype Adott egy összetett tároló: std::map<int, std::vector<string> > m; Járjuk végig egy iterátorral: std::map<int, std::vector<string> >::iterator iter = m.begin(); Használjuk az auto kulcsszót: auto iter = m.begin(); Majd a fordító kitalálja az iter típusát az m.begin() visszatérési értékének típusából. 9

auto, decltype Változó, visszatérési érték típusának lekérdezése: int x; decltype(x) y = 5; Főleg templatek használatakor lehet nagyon hasznos. 10

nullptr A nullpointer hagyományosan: 0 vagy NULL #ifndef cplusplus #define NULL ((void *)0) #else /* C++ */ #define NULL 0 #endif /* C++ */ Azaz, C++-ban a NULL típusa int! Melyik függvény hívódik meg? void foo(int) { void foo(char *) { [...] foo(null); 11

nullptr Megoldás: A C++11-ben bevezették a nullptr kulcsszót. Implicit kasztolható más pointerre és boolra. Saját típusa van: decltype(nullptr), vagy std::nullptr_t Írhatunk olyan függvényt, amely csak nullptr paramétert fogad el: void foo(std::nullptr_t) { 12

constexpr Számítsuk ki egy egész szám kettes alapú logaritmusát metaprogramozással: 13

constexpr Számítsuk ki egy egész szám kettes alapú logaritmusát metaprogramozással: template <unsigned n> struct Logarithm { enum { value = 1 + Logarithm<n / 2>::value ; ; template <> struct Logarithm<1> { enum { value = 0 ; ; cout << Logarithm<512>::value << endl; 14

constexpr Számítsuk ki egy egész szám kettes alapú logaritmusát metaprogramozással: template <unsigned n> struct Logarithm { enum { value = 1 + Logarithm<n / 2>::value ; ; template <> struct Logarithm<1> { enum { value = 0 ; ; cout << Logarithm<512>::value << endl; Használjunk konstans kifejezést: constexpr unsigned int log2(unsigned int n) { return n == 1? 0 : 1 + log2(n / 2); cout << log2(512) << endl; 15

foreach Írassuk ki egy vector minden elemét: vector<int> v; [ ] auto iter = v.begin(); auto iterend = v.end(); for (; iter!= iterend; iter++) { cout << *iter << endl; 16

foreach Írassuk ki egy vector minden elemét: vector<int> v; [ ] auto iter = v.begin(); auto iterend = v.end(); for (; iter!= iterend; iter++) { cout << *iter << endl; Ugyanez tömörebben: for (auto i: v) { cout << i << endl; 17

foreach Növeljük egy vector minden elemét: vector<int> v; [ ] auto iter = v.begin(); auto iterend = v.end(); for (; iter!= iterend; iter++) { cout << iter++ << endl; 18

foreach Növeljük egy vector minden elemét: vector<int> v; [ ] auto iter = v.begin(); auto iterend = v.end(); for (; iter!= iterend; iter++) { cout << iter++ << endl; Ugyanez tömörebben: for (auto & i: v) { cout << i++ << endl; 19

foreach A foreach saját osztályra is működik, ha: Az osztálynak van begin() és end() függvénye Ezen függvények valamilyen iterátort adnak vissza Az iterátor rendelkezik ++,!= és * (indirekció) operátorokkal 20

Újdonságok osztályokban: értékadás deklarációban Adattagnak értékadás deklarációban: class Person { private: int age = 20; string name = "Dave"; ; Amennyiben a konstruktorban nem adunk értéket valamely változónak, a deklarációban megadott értékeket veszi fel. 21

Újdonságok osztályokban: delete függvény Bizonyos függvények meghívása letiltható: class Person { public: void foo() = delete; void foo(int) { template <class T> void foo(t) = delete; ; A fenti példában csak int típusú paraméterrel hívhatjuk meg a foo függvényt! További példa: Letiltható a másoló konstruktor, értékadó operátor is. 22

Újdonságok osztályokban: move konstruktor Balérték: Minden olyan kifejezés, amely megcímezhető, és értéket adhatunk neki a = 1; // a itt most balérték Jobbérték: Ideiglenes objektum string getname() { return "Joe"; string name = getname(); Itt a name balérték, viszont a visszatérési érték jobbérték 23

Újdonságok osztályokban: move konstruktor Balérték referencia: típus & név Jobbérték referencia: típus && név string name1 = getname(); string & name2 = getname(); const string & name3 = getname(); string && name4 = getname(); const string && name5 = getname(); A jobbérték referenciával hivatkozhatunk az ideiglenes objektumra Balérték referenciából jobbérték referencia: Vector v; Vector && vr = std::move(v); 24

Újdonságok osztályokban: move konstruktor Mi történik ekkor? string getname() { return "Joe"; string name = getname(); 25

Újdonságok osztályokban: move konstruktor Mi történik ekkor? string getname() { return "Joe"; string name = getname(); Létrejön egy ideiglenes, string típusú objektum (konstruktor, memóriafoglalás, másolás) 26

Újdonságok osztályokban: move konstruktor Mi történik ekkor? string getname() { return "Joe"; string name = getname(); Meghívódik a copy konstruktor, és létrejön a name objektum: újabb memóriafoglalás, másolás Végül az ideiglenes objektum felszabadul 27

Újdonságok osztályokban: move konstruktor Csak egyszer foglaljunk memóriát! Nem lemásoljuk a visszatérési értéket, hanem átmozgatjuk -> move konstruktor Paramétere: egy jobbérték referencia Tipikus használata: Lemásoljuk az adattagokat (a pointereket is), majd az eredeti objektum változóit kinullázzuk Az objektumot átmozgattuk, az eredeti objektumnál a destruktor nem csinál semmit 28

Újdonságok osztályokban: move konstruktor class Vector { public: Vector() { data = new double[10]; Vector(Vector && right) { data = right.data; right.data = nullptr; ~Vector() { delete [] data; data = nullptr; private: double * data; ; 29

Újdonságok osztályokban: Vector getvector() { Vector v; return v; move konstruktor int main() { Vector v0 = getvector(); 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 Lefut a Vector konstruktora, az pedig lefoglalja a dinamikus tömböt. v data 30

Újdonságok osztályokban: Vector getvector() { Vector v; return v; move konstruktor int main() { Vector v0 = getvector(); 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 Létrejön egy ideiglenes objektum, ez a move konstruktor által jön létre. v data data? 31

Újdonságok osztályokban: move konstruktor Vector(Vector && right) { data = right.data; right.data = nullptr; 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 v=right data data Az újonnan létrejövő objektum lemásolja a pointert. 32

Újdonságok osztályokban: move konstruktor Vector(Vector && right) { data = right.data; right.data = nullptr; 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 v=right data data A régi objektum pointerét nullázzuk, hiszen az úgyis felszabadul. 33

Újdonságok osztályokban: Vector getvector() { Vector v; return v; move konstruktor int main() { Vector v0 = getvector(); 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 data Létrejön a v0 változó, mégpedig szintén egy move konstruktor hívással, ahol most az előbb létrejött vektor lesz a konstruktor paramétere v0 data 34

Újdonságok osztályokban: move konstruktor Vector(Vector && right) { data = right.data; right.data = nullptr; 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 v0 right data data int main() { Vector v0 = getvector(); Lemásoljuk a pointert. 35

Újdonságok osztályokban: move konstruktor Vector(Vector && right) { data = right.data; right.data = nullptr; 3, 5, 4, 3, 1, 0, 1, 6, 7, 8, 2, 10 v0 right data data int main() { Vector v0 = getvector(); Majd nullázzuk az ideiglenes objektum pointerét, hiszen úgyis felszabadul. 36

Újdonságok osztályokban: move = operátor Ha a visszatérési értéket olyan változóban tároljuk, amely már létezik, akkor az = operátor fut le Létezik move = operátor, amely szintén jobbérték referenciát kap paraméterként A move konstruktornál annyiban több, hogy az aktuális változó tartalmát felszabadítja 37

Újdonságok osztályokban: move = operátor class Vector { public: [ ] Vector & operator=(vector && right) { if (&right == this) { return *this; delete [] data; data = right.data; right.data = nullptr; [ ] 38

Eközben a gcc-ben Gcc-t alapértelmezett paraméterekkel használva az alábbi kód esetében csak egy konstruktor és egy destruktor fut le: Vector getvec() { Vector v; return v; int main() { Vector vec = getvec(); A fordító optimalizál (copy elision) Kikapcsolható a -fno-elide-constructors kapcsolóval (de nem érdemes ) 39

Típusos enum Probléma: enum GYUMOLCSOK {ALMA, KORTE, NARANCS; enum SZINEK {PIROS, KEK, NARANCS; A NARANCS két enumban is szerepel Megoldás: enum class GYUMOLCSOK {ALMA, KORTE, NARANCS; enum class SZINEK {PIROS, KEK, NARANCS; enum class SZINEK szin = SZINEK::NARANCS; Egyértelműen kifejezhetjük, hogy az egyik enum típus nem kompatibilis a másikkal 40

Az enum mérete Az enum mérete alapértelmezetten az int méretével egyenlő A méret lecserélhető bármely egész típus méretére: enum class GYUMOLCSOK : char {ALMA, KORTE; 41

Lambda kifejezések Írjunk függvényt, amely megszámlálja, hogy hány olyan elem van egy tömbben, amelyekre igaz egy bizonyos tulajdonság! A függvény legyen általános célú. Régi módszerek: Függvény pointer átadása Funktorok alkalmazása 42

Lambda kifejezések Új módszer: #include <functional> int szamol(int * v, int meret, std::function<bool (int)> talalt) { int i; int mennyi = 0; for (i = 0; i < meret; i++) { if (talalt(v[i])) { mennyi++; return mennyi; int main() { int vec[10] = {3, 5, 1, 3, 5, 1, 7, 8, 4, 1; auto paros = [](int num)->bool{return num % 2 == 0;; int parosak = szamol(vec, 10, paros); [ ] 43

Lambda kifejezések Másképp: #include <functional> int szamol(int * v, int meret, std::function<bool (int)> talalt) { int i; int mennyi = 0; for (i = 0; i < meret; i++) { if (talalt(v[i])) { mennyi++; return mennyi; int main() { int vec[10] = {3, 5, 1, 3, 5, 1, 7, 8, 4, 1; int parosak = szamol(vec, 10, [](int num)->bool{ return num % 2 == 0; ); [ ] 44

Lambda kifejezések Szintaktika: [<változók elfogása>] (<paraméterek>) -><visszatérési érték típusa>{<függvény törzs> Változók elfogása: Segítségével a függvényből hivatkozhatunk olyan változókra, amelyek ott léteznek, ahol megírtuk a lambda kifejezést 45

Lambda kifejezések Példa változók elfogására: int alma = 4; int vec[10] = {3, 5, 1, 3, 5, 1, 7, 8, 4, 1; int nagyok = szamol(vec, 10, [=](int num)->bool { return num > 3+alma; ); Az [=] jelentése: a függvény megkapja minden, a lambda kifejezés környezetében elérhető változó másolatát 46

Lambda kifejezések További lehetőségek változók elfogására: [] semmit nem kapunk el [&] a változókat referencia szerint kapjuk el [<változónév>] egy konkrét változók kapunk el érték szerint [=, &<változónév>] minden változót érték szerint kapunk el, kivéve egyet, amelyet referencia szerint [this] a befoglaló objektum címét fogjuk el 47

Struktúra inicializálás A struktúrákat mostantól tömörebb formában is inicializálhatjuk: struct Valami { int a; char b; double c; ; struct Masik { Valami v; int d; ; int main() { Masik m = {{2, 'b', 4.4, 4; [ ] 48

Struktúra inicializálás A struktúrákat mostantól tömörebb formában is inicializálhatjuk: struct Valami { int a; char b; double c; ; struct Masik { Valami v; int d; ; int main() { Masik m = {{2, 'b', 4.4, 4; [ ] 49

Inicializáló lista Gyorsan töltsünk fel egy vectort néhány elemmel, régi módszer: std::vector<int> v; v.push_back(3); v.push_back(2); v.push_back(7); Új módszer: std::vector<int> v = {3, 2, 7; 50

Inicializáló lista A saját osztályunkat is felkészíthetjük arra, hogy inicializáló listát kap A fordító felismeri az inicializáló listát A listát beágyazza egy std::initializer_list típusú objektumba Az objektumot pedig megkapja a függvényünk paraméterként 51

Inicializáló lista Vector(const std::initializer_list<double> & list) { data = new double[ list.size() ]; auto iter = list.begin(); auto iterend = list.end(); unsigned int index = 0; for (; iter!= iterend; iter++, index++) { data[index] = *iter; Vagy: Vector(const std::initializer_list<double> & list) { data = new double[ list.size() ]; unsigned int index = 0; for (auto value: list) { data[index] = value; 52

Smart pointerek Header: memory Okos pointerek: korábban std::auto_ptr Eltárol egy pointert, és ha a változó megszűnik, automatikusan felszabadítja a pointer által mutatott objektumot Ha lemásoljuk az objektumot, akkor a másolat tárolja az eredeti pointert, az eredeti objektum nullpointert tartalmaz 53

Smart pointerek std::auto_ptr<vector> ptr1(new Vector); std::auto_ptr<vector> ptr2; cout << ptr1.get() << endl; cout << ptr2.get() << endl; ptr2 = ptr1; cout << ptr1.get() << endl; cout << ptr2.get() << endl; Kimenet: konstruktor 0x661600 0 0 0x661600 destruktor 54

Smart pointerek std::unique_ptr: ugyanaz, mint az std::auto_ptr, csupán nem azt mondjuk hogy lemásoljuk a pointereket, hanem átmozgatjuk A C++11-ben érvénytelenítettnek számít az std::auto_ptr Az std::unique_ptr copy constructora és a = operátorok deleted függvények 55

Smart pointerek std::unique_ptr<vector> ptr1(new Vector); std::unique_ptr<vector> ptr2; cout << ptr1.get() << endl; cout << ptr2.get() << endl; ptr2 = ptr1; ptr2 = std::move(ptr1); cout << ptr1.get() << endl; cout << ptr2.get() << endl; 56

Smart pointerek std::shared_ptr: Több shared_ptr képes tárolni ugyanazt a pointert, ám referencia számlálást alkalmaz Ha megszűnik minden olyan shared_ptr, amely az adott objektumra hivatkozik, csak akkor szabadul fel a dinamikus objektum Probléma lehet abból ha az objektumok körkörösen hivatkoznak egymásra 57

Smart pointerek std::shared_ptr<vector> ptr1(new Vector); std::shared_ptr<vector> ptr2; cout << ptr1.get() << endl; cout << ptr2.get() << endl; ptr2 = ptr1; cout << ptr1.get() << endl; cout << ptr2.get() << endl; Kimenet: konstruktor 0x6b1600 0 0x6b1600 0x6b1600 destruktor 58

Smart pointerek x hivatkozik y-ra, y pedig x-re, hiába töröljük egyiket, vagy a másikat, életben tartják egymást struct A { ~A() { cout << "Destruktor" << endl; std::shared_ptr<a> ptr; ; int main() { std::shared_ptr<a> x=std::make_shared<a>(); std::shared_ptr<a> y=std::make_shared<a>(); x->ptr = y; y->ptr = x; 59

Smart pointerek std::weak_ptr: Ha az objektumra már csak egy weak_ptr hivatkozik, akkor az az objektum felszabadul Megtörhető a körkörös hivatozás A weak_ptr lemásolhat egy shared_ptr-t A shared_ptr csak a weak_ptr lock() függvényén keresztül másolhat le egy weak_ptr-t Utóbbi esetben mindig ellenőrizni kell, hogy a másolat shared_ptr érvényes memóriaterületre mutat-e 60

Smart pointerek A korábbi körkörös hivatkozás feloldása: struct A { ~A() { cout << "Destruktor" << endl; std::shared_ptr<a> ptr; std::weak_ptr<a> ptrweak; ; int main() { std::shared_ptr<a> x=std::make_shared<a>(); std::shared_ptr<a> y=std::make_shared<a>(); x->ptr = y; y->ptrweak = x; 61

Szálkezelés Új szálakat hozhatunk létre az std::thread osztály segítségével Meg kell adnunk azt a függvényt, amelyet az új szál futtat #include <thread> #include <iostream> void foo() { std::cout << "thread" << std::endl; int main() { std::thread t1(foo); std::thread t2(foo); std::thread t3(foo); t1.join(); // megvárjuk, amíg lefut t2.join(); // megvárjuk, amíg lefut t3.join(); // megvárjuk, amíg lefut 62

Szálkezelés Osztott változókat mutexekkel védhetünk A mutex is osztott A szálak megpróbálják lefoglalni a mutexet, de egyszerre csak egynek sikerül, a többi addig várakozik int a = 0; std::mutex m; void foo() { m.lock(); a = rand() % 10; m.unlock(); 63

Szálkezelés Egy statikus változó csak egy példányban létezik Minden szál ugyanazt a statikus változót látja A thread_local kulcsszóval minden szál saját példányt kap az adott statikus változóból A thread_local változó a szál létrehozásakor jön létre, és a szál végén megsemmisül 64

Szálkezelés thread_local használatával: #include <iostream> #include <thread> thread_local int b; class A { public: static thread_local int a; ; thread_local int A::a = 10; std::mutex m; void foo() { m.lock(); Kimenet: 10 0x9431a4 0x9431dc 10 0x23c8124 0x23c8134 10 0x23c8144 0x23c8114 cout << A::a++ << " " << &A::a << endl; cout << &b << endl; m.unlock(); 65

Szálkezelés thread_local nélkül: #include <iostream> #include <thread> int b; class A { public: static int a; ; int A::a = 10; std::mutex m; void foo() { m.lock(); Kimenet: 10 0x404004 0x40903c 11 0x404004 0x40903c 12 0x404004 0x40903c cout << A::a++ << " " << &A::a << endl; cout << &b << endl; m.unlock(); 66

Köszönöm a figyelmet! A publikáció az Európai Unió, Magyarország és az Európai Szociális Alap társfinanszírozása által biztosított forrásból a TÁMOP-4.2.2.C-11/1/KONV-2012-0004 azonosítójú "Nemzeti kutatóközpont fejlett infokommunikációs technológiák kidolgozására és piaci bevezetésére" című projekt támogatásával jött létre. 67