C++11

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2020. szeptember 15-én felülvizsgált verziótól ; az ellenőrzések 24 szerkesztést igényelnek .

C++11 [1] [2] vagy ISO/IEC 14882:2011 [3] (a szabvány kidolgozása során C++0x kódneve volt [4] [5] ) – a szabvány új verziója a C++ nyelvi szabvány a korábban érvényes ISO /IEC 14882:2003 helyett. Az új szabvány kiegészítéseket tartalmaz a nyelv magjához és a szabványos könyvtár kiterjesztését, beleértve a TR1 nagy részét  - kivéve talán a speciális matematikai függvények könyvtárát. A szabványok új verziói néhány más C++ szabványosítási dokumentummal együtt megjelennek az ISO C++ bizottság honlapján [6] . C++ programozási példák

A programozási nyelvek képességeinek fokozatos fejlesztése zajlik (jelenleg a C++11 után a következő szabványos bővítmények jelentek meg: C++14, C++17, C++20). Ez a folyamat elkerülhetetlenül kompatibilitási problémákat okoz a meglévő kóddal. Az N3290 nemzetközi szabvány végleges tervezetének C.2 függeléke [diff.cpp03] leír néhány inkompatibilitást a  C++11 és a C++03 között.

A szabvány javasolt módosításai

Mint már említettük, a változtatások a C++ magot és annak szabványos könyvtárát is érintik.

A jövőbeni szabvány egyes szakaszainak kidolgozásakor a bizottság számos szabályt alkalmazott:

Figyelmet fordítanak a kezdőkre, akik mindig a programozók többségét teszik ki. Sok kezdő nem törekszik a C ++ ismereteinek elmélyítésére, és csak szűk specifikus feladatokon dolgozik [7] . Ezen túlmenően, tekintettel a C++ sokoldalúságára és széleskörű használatára (beleértve az alkalmazások és a programozási stílusok sokféleségét), még a szakemberek is új programozási paradigmákkal találkozhatnak .

Az alapnyelv kiterjesztése

A bizottság elsődleges feladata a C++ nyelv magjának fejlesztése. A kernel jelentősen javult, többszálú támogatással bővült, javult az általános programozás támogatása , egységesítették az inicializálást, és dolgoztak a teljesítmény javításán.

A kényelem kedvéért a kernel szolgáltatásai és módosításai három fő részre oszlanak: teljesítményjavítások, kényelmi fejlesztések és új funkciók. Az egyes elemek több csoportba is tartozhatnak, de csak egy - a legmegfelelőbb - leírására kerül sor.

Teljesítményjavítás

Ezeket a nyelvi összetevőket a memória többletterhelésének csökkentése vagy a teljesítmény javítása érdekében vezették be.

Ideiglenes objektumhivatkozások és áthelyezési szemantika

A C++ szabvány szerint egy kifejezés kiértékeléséből származó ideiglenes objektum átadható függvényeknek, de csak állandó hivatkozással ( const & ). A függvény nem tudja megállapítani, hogy az átadott objektum ideiglenesnek és módosíthatónak tekinthető-e (egy ilyen hivatkozással is átadható const objektum nem módosítható (legálisan)). Ez nem probléma az olyan egyszerű struktúráknál, mint a complex, de az összetett típusoknál, amelyek memóriafoglalást-felszabadítást igényelnek, egy ideiglenes objektum megsemmisítése és egy állandó létrehozása időigényes lehet, míg a mutatókat egyszerűen átadhatja közvetlenül.

A C++11 egy új típusú hivatkozást vezet be , az rvalue referenciát .  Deklarációja : type && . Az új túlterhelés-feloldási szabályok lehetővé teszik, hogy különböző túlterhelt függvényeket használjon a nem állandó ideiglenes objektumokhoz, amelyeket rértékek jelölnek, valamint az összes többi objektumhoz. Ez az innováció lehetővé teszi az úgynevezett mozgásszemantika megvalósítását .

Például std::vector egy egyszerű burkoló egy C-tömb körül, és egy változó, amely tárolja a méretét. A másoláskonstruktor std::vector::vector(const vector &x)létrehoz egy új tömböt, és másolja az információkat; az átviteli konstruktor std::vector::vector(vector &&x)egyszerűen kicserélheti a hosszt tartalmazó mutatókat és változókat.

Példa a hirdetésre.

sablon < osztály T > osztályvektor _ { vektor ( const vektor & ); // Konstruktor (lassú) vektor másolása ( vektor && ); // Konstruktor átvitele ideiglenes objektumból (gyors) vektor & operátor = ( const vektor & ); // Szabályos hozzárendelés (lassú) vektor & operátor = ( vektor && ); // Ideiglenes objektum áthelyezése (gyors) void foo () & ; // Csak elnevezett objektumon működő függvény (lassú) void foo () && ; // Csak ideiglenes objektumhoz működő függvény (gyors) };

Az ideiglenes hivatkozásokhoz számos minta kapcsolódik, amelyek közül a két legfontosabb a és . Az első egy szabályos nevű objektumot ideiglenes hivatkozássá tesz: moveforward

// std::move sablon példa void bar ( std :: string && x ) { statikus std :: stringsomeString ; _ someString = std :: move ( x ); // az x=string& függvényen belül, ezért a második lépés a mozgatási hozzárendelés meghívásához } std :: stringy ; _ bár ( std :: mozgás ( y )); // Az első lépés a string-et string&&-vé alakítja a hívósávhoz

A sablont csak a metaprogramozásban használják, explicit template paramétert igényel (két megkülönböztethetetlen túlterhelése van), és két új C++ mechanizmushoz kapcsolódik. Az első a linkragasztás: , majd . Másodszor, a fenti bar() függvénynek szüksége van egy ideiglenes objektumra a külső oldalon, de belül az x paraméter egy közönséges nevű (lvalue) a tartaléknak, ami lehetetlenné teszi a string& paraméter automatikus megkülönböztetését a string&& paramétertől. Egy közönséges nem sablon függvényben a programozó elhelyezheti a move(t) vagy nem, de mi a helyzet a sablonnal? forwardusing One=int&&; using Two=One&;Two=int&

// példa a sablon használatára std::forward class Obj { std :: stringfield ; _ sablon < classT > _ Obj ( T && x ) : mező ( std :: előre < T > ( x )) {} };

Ez a konstruktor lefedi a szokásos (T=string&), másolás (T=const string&) és mozgatási (T=string) túlterheléseket referencia ragasztással. A forward pedig nem csinál semmit, vagy kibővül std::move-ra a T típusától függően, és a konstruktor másolja, ha másolatról van szó, és mozog, ha mozgásról van szó.

Általános állandó kifejezések

A C++-ban mindig is az állandó kifejezések fogalma volt. Így az olyan kifejezések, mint a 3+4 , mindig ugyanazokat az eredményeket adták vissza anélkül, hogy mellékhatásokat okoztak volna. A konstans kifejezések önmagukban kényelmes módot biztosítanak a C++ fordítók számára a fordítási eredmény optimalizálására. A fordítók az ilyen kifejezések eredményeit csak fordításkor értékelik ki, és a már kiszámított eredményeket tárolják a programban. Így az ilyen kifejezések csak egyszer kerülnek kiértékelésre. Van néhány olyan eset is, amikor a nyelvi szabvány állandó kifejezések használatát írja elő. Ilyen esetek lehetnek például külső tömbök vagy enumértékek meghatározásai.


int GiveFive () { return 5 ;} int valami_érték [ GiveFive () + 7 ]; // 12 egész számból álló tömb létrehozása; tiltott C++-ban

A fenti kód illegális a C++-ban, mert a GiveFive() + 7 technikailag nem egy fordítási időben ismert állandó kifejezés. A fordító éppen nem tudja, hogy a függvény ténylegesen egy állandót ad vissza futási időben. Ennek a fordítói érvelésnek az az oka, hogy ez a függvény befolyásolhatja egy globális változó állapotát, meghívhat egy másik, nem állandó futásidejű függvényt, és így tovább.

A C++11 bevezeti a constexpr kulcsszót , amely lehetővé teszi a felhasználó számára, hogy megbizonyosodjon arról, hogy egy függvény vagy egy objektumkonstruktor fordítási időállandót ad vissza. A fenti kód átírható így:

constexpr int GiveFive () { return 5 ;} int valami_érték [ GiveFive () + 7 ]; // 12 egész számból álló tömb létrehozása; megengedett a C++11

Ez a kulcsszó lehetővé teszi a fordító számára, hogy megértse és ellenőrizze, hogy a GiveFive állandót ad- e vissza.

A constexpr használata nagyon szigorú korlátozásokat ír elő a függvény műveleteire:

  1. egy ilyen függvénynek értéket kell visszaadnia;
  2. a függvény törzsének a visszatérési kifejezés formájúnak kell lennie ;
  3. a kifejezésnek konstansokból és/vagy egyéb constexpr függvényekkell állnia
  4. a constexpr-rel jelölt függvény nem használható addig, amíg az aktuális fordítási egységben nem definiáljuk.

A szabvány korábbi verziójában csak integer vagy enum típusú változók használhatók konstans kifejezésekben. A C++11 nyelvben ez a korlátozás megszűnik azoknál a változóknál, amelyek definícióját a constexpr kulcsszó előzi meg:

constexpr double accelerationOfGravity = 9,8 ; constexpr double moonGravity = accelerationOfGravity / 6 ;

Az ilyen változókat már implicit módon a const kulcsszó jelöli . Csak konstans kifejezések eredményeit vagy az ilyen kifejezések konstruktorait tartalmazhatják.

Ha a felhasználó által definiált típusokból állandó értékeket kell létrehozni, akkor az ilyen típusú konstruktorok a constexpr segítségével is deklarálhatók . A konstans kifejezés-konstruktort, a konstans függvényekhez hasonlóan, szintén meg kell határozni az aktuális fordítási egységben való első használat előtt. Egy ilyen konstruktornak üres testtel kell rendelkeznie, és egy ilyen konstruktornak csak konstansokkal kell inicializálnia a típusának tagjait.

Változások az egyszerű adatok meghatározásában

A szabványos C++-ban csak azok a struktúrák tekinthetők egyszerű régi adattípusnak ( POD), amelyek megfelelnek egy bizonyos szabályrendszernek. Jó okunk van elvárni, hogy ezeket a szabályokat kiterjesszék, hogy több típust is POD-nak tekintsenek. Az ezeknek a szabályoknak megfelelő típusok használhatók C-kompatibilis objektumréteg-megvalósításban, azonban a C++03 ezen szabályok listája túlságosan korlátozó.

A C++11 számos szabályt lazít az egyszerű adattípusok meghatározásával kapcsolatban.

Egy osztály akkor tekinthető egyszerű adattípusnak, ha triviális , szabványos elrendezésű ( standard-layout ) , és ha az összes nem statikus adattag típusa is egyszerű adattípus.

A triviális osztály olyan osztály, amely:

  1. triviális alapértelmezett konstruktort tartalmaz,
  2. nem tartalmaz nem triviális másolatkonstruktorokat,
  3. nem tartalmaz nem triviális mozgáskonstruktorokat,
  4. nem tartalmaz nem triviális másolás-hozzárendelési operátorokat,
  5. nem tartalmaz nem triviális mozgás hozzárendelési operátorokat,
  6. triviális destruktort tartalmaz.

A standard elhelyezésű osztály az az osztály, amely:

  1. nem tartalmaz egy egyedileg elhelyezett osztálytípus (vagy az ilyen típusú elemek tömbje) vagy referenciatípus nem statikus adattagjait,
  2. nem tartalmaz virtuális függvényeket,
  3. nem tartalmaz virtuális alaposztályokat,
  4. azonos hozzáférési típussal ( public, private, protected) rendelkezik az összes nem statikus adattaghoz,
  5. nem rendelkezik nem szabványos elhelyezésű alaposztályokkal,
  6. nem olyan osztály, amely egyidejűleg öröklött és nem örökölt nem statikus adattagokat tartalmaz, vagy nem statikus adattagokat tartalmaz, amelyek egyszerre több alaposztályból örököltek,
  7. nem rendelkezik ugyanolyan típusú alaposztályokkal, mint az első nem statikus adattag (ha van ilyen).

Az összeállítás felgyorsítása

Külső sablonok

A szabványos C++-ban a fordítónak példányosítania kell egy sablont, amikor találkozik annak teljes szakosodásával egy fordítási egységben. Ez jelentősen megnövelheti a fordítási időt, különösen akkor, ha a sablon ugyanazokkal a paraméterekkel példányosodik nagyszámú fordítási egységben. Jelenleg nem lehet megmondani a C++-nak, hogy ne legyen példányosítás.

A C++11 bevezette a külső sablonok ötletét. A C++-nak már van egy szintaxisa, amely megmondja a fordítónak, hogy egy sablont egy bizonyos ponton példányosítani kell:

sablon osztály std :: vektor < MyClass > ;

A C++ nem képes megakadályozni, hogy a fordító egy sablont példányosítson a fordítási egységben. A C++11 egyszerűen kiterjeszti ezt a szintaxist:

extern template class std :: vektor < MyClass > ;

Ez a kifejezés azt mondja a fordítónak , hogy ne példányosítsa a sablont ebben a fordítási egységben.

Továbbfejlesztett használhatóság

Ezek a funkciók a nyelv egyszerűbb használatát hivatottak megkönnyíteni. Lehetővé teszik a típusbiztonság erősítését, a kódduplikáció minimalizálását, a kóddal való visszaélések megnehezítését és így tovább.

Inicializálási listák

Az inicializálási listák fogalma a C++-ba a C-ből származik. Az ötlet az, hogy egy struktúra vagy tömb létrehozható úgy, hogy argumentumlistát adunk át abban a sorrendben, ahogyan a struktúra tagjai definiálva vannak. Az inicializálási listák rekurzívak, ami lehetővé teszi, hogy struktúrák tömbjeihez és beágyazott struktúrákat tartalmazó struktúrákhoz használják.

struct objektum { úszó először ; int másodperc ; }; Objektum skalár = { 0,43f , 10 }; // egy objektum, első=0.43f és második=10 Object anArray [] = {{ 13.4f , 3 }, { 43.28f , 29 }, { 5.934f , 17 }}; // három objektum tömbje

Az inicializálási listák nagyon hasznosak a statikus listákhoz, és akkor, ha egy struktúrát egy adott értékre szeretne inicializálni. A C++ konstruktorokat is tartalmaz, amelyek tartalmazhatják az objektumok inicializálásának általános munkáját. A C++ szabvány lehetővé teszi inicializálási listák használatát struktúrákhoz és osztályokhoz, feltéve, hogy azok megfelelnek a Plain Old Data (POD) definíciójának. A nem POD osztályok nem használhatnak inicializálási listákat az inicializáláshoz, beleértve a szabványos C++ konténereket, például vektorokat.

A C++11 társította az inicializálási listák fogalmát és egy std::initializer_list nevű sablonosztályt . Ez lehetővé tette a konstruktorok és más függvények számára, hogy paraméterként inicializálási listákat kapjanak. Például:

osztály SequenceClass { nyilvános : SequenceClass ( std :: inicializáló_lista < int > lista ); };

Ez a leírás lehetővé teszi egy SequenceClass létrehozását egész számok sorozatából az alábbiak szerint:

SequenceClass someVar = { 1 , 4 , 5 , 6 };

Ez bemutatja, hogyan működik egy speciális konstruktor egy inicializálási listához. Az ilyen konstruktorokat tartalmazó osztályokat az inicializálás során speciális módon kezeljük (lásd alább ).

Az std::initializer_list<> osztály a C++11 Standard Library-ben van definiálva. Ennek az osztálynak az objektumait azonban csak a C++11 fordító tudja statikusan létrehozni a {} zárójeles szintaxis használatával. A lista létrehozása után másolható, ez azonban referenciaként történik. Az inicializálási lista állandó: sem tagjai, sem adatai nem módosíthatók a létrehozás után.

Mivel az std::initializer_list<> egy teljes értékű típus, nem csak konstruktorokban használható. A közönséges függvények argumentumként használhatják a begépelt inicializálási listákat, például:

void FunctionName ( std :: inicializáló_lista < float > lista ); FunctionName ({ 1.0f , -3.45f , -0.4f });

A szabványos tárolók a következőképpen inicializálhatók:

std :: vektor < std :: string > v = { " xyzzy" , "plugh" , "abracadabra " }; std :: vektor < std :: string > v { " xyzzy" , "plugh" , "abracadabra " }; Általános inicializálás

A C++ szabvány számos problémát tartalmaz a típusinicializálással kapcsolatban. A típusok inicializálásának többféle módja van, és nem mindegyik vezet ugyanarra az eredményre. Például egy inicializáló konstruktor hagyományos szintaxisa függvénydeklarációnak tűnhet, és fokozottan ügyelni kell arra, hogy a fordító ne hibásan elemezze azt. Csak aggregált típusok és POD típusok inicializálhatók aggregált inicializálókkal (a fajta SomeType var = {/*stuff*/};).

A C++11 olyan szintaxist biztosít, amely lehetővé teszi az inicializálás egyetlen formájának használatát minden típusú objektumhoz az inicializálási lista szintaxisának kiterjesztésével:

struct BasicStruct { int x ; dupla y ; }; struct AltStruct { AltStruct ( int x , dupla y ) : x_ ( x ), y_ ( y ) {} privát : int x_ ; dupla y_ ; }; BasicStruct var1 { 5 , 3.2 }; AltStruct var2 { 2 , 4.3 };

A var1 inicializálása pontosan ugyanúgy működik, mint az aggregátumok inicializálása, azaz minden objektum inicializálása a megfelelő érték kimásolásával történik az inicializálási listáról. Ha szükséges, implicit típuskonverziót alkalmazunk. Ha a kívánt átalakítás nem létezik, a forráskód érvénytelennek minősül. A var2 inicializálása során a konstruktor meghívásra kerül.

Lehetséges így kódot írni:

struct IdString { std :: karakterláncnév ; _ int azonosító ; }; IdString GetString () { return { "SomeName" , 4 }; // Vegye figyelembe az explicit típusok hiányát }

Az általános inicializálás nem helyettesíti teljesen a konstruktor inicializálási szintaxisát. Ha egy osztálynak van olyan konstruktora, amely egy inicializálási listát ( TypeName(initializer_list<SomeType>); ) vesz argumentumként, akkor az elsőbbséget élvez a többi objektum-létrehozási lehetőséggel szemben. Például a C++11-ben az std::vector tartalmaz egy konstruktort, amely egy inicializálási listát vesz argumentumként:

std :: vektor < int > theVec { 4 };

Ez a kód egy konstruktorhívást eredményez, amely egy inicializálási listát vesz argumentumként, nem pedig egy egyparaméteres konstruktort, amely egy adott méretű tárolót hoz létre. A konstruktor meghívásához a felhasználónak a szabványos konstruktorhívási szintaxist kell használnia.

Típus következtetés

A szabványos C++-ban (és C-ben) a változó típusát kifejezetten meg kell adni. A sablontípusok és a sablon metaprogramozási technikák megjelenésével azonban egyes értékek típusa, különösen a függvény visszatérési értékei nem határozhatók meg könnyen. Ez nehézségekhez vezet a közbenső adatok változókban való tárolásában, néha szükséges lehet egy adott metaprogramozási könyvtár belső szerkezetének ismerete.

A C++11 két módszert kínál ezeknek a problémáknak a enyhítésére. Először is, egy kifejezetten inicializálható változó definíciója tartalmazhatja az auto kulcsszót . Ennek eredményeként létrejön egy, az inicializálási érték típusának megfelelő változó:

auto someStrangeCallableType = std :: bind ( & SomeFunction , _2 , _1 , someObject ); auto otherVariable = 5 ;

A someStrangeCallableType típus lesz az a típus, amelyet a sablonfüggvény konkrét megvalósítása visszaad std::bindaz adott argumentumokhoz. Ezt a típust a fordító könnyen meghatározza a szemantikai elemzés során, de a programozónak némi kutatást kell végeznie a típus meghatározásához.

Az otherVariable típus is jól definiált, de a programozó is könnyen meghatározhatja. Ez a típus int , ugyanaz, mint egy egész szám.

Ezenkívül a decltype kulcsszó használható egy kifejezés típusának meghatározására fordításkor . Például:

int someInt ; decltype ( someInt ) otherIntegerVariable = 5 ;

A decltype használata a leghasznosabb az auto -val együtt , mivel az autoként deklarált változó típusát csak a fordító ismeri. Ezenkívül a decltype használata nagyon hasznos lehet olyan kifejezésekben, amelyek operátortúlterhelést és sablonspecializációt használnak.

autokódredundancia csökkentésére is használható. Például ahelyett, hogy:

for ( vektor < int >:: const_iterator itr = myvec . cbegin (); itr != myvec . cend (); ++ itr )

a programozó ezt írhatja:

for ( auto itr = myvec . cbegin (); itr != myvec . cend (); ++ itr )

A különbség különösen akkor válik szembetűnővé, ha egy programozó nagyszámú különböző tárolót használ, bár még mindig van egy jó módszer a redundáns kód csökkentésére - a typedef.

A decltype jellel jelölt típus eltérhet az auto által kikövetkeztetett típustól .

#include <vektor> int main () { const std :: vektor < int > v ( 1 ); auto a = v [ 0 ]; // írja be a - int decltype ( v [ 0 ]) b = 1 ; // type b - const int& (visszatérési érték // std::vector<int>::operator[](size_type) const) auto c = 0 ; // írja be a c - int auto d = c ; // típus d - int decltype ( c ) e ; // típus e - int, a c nevű entitás típusa decltype (( c )) f = c ; // az f típus int&, mert (c) egy lvvalue decltype ( 0 ) g ; // a g típus int, mivel a 0 egy rérték } For-loop egy gyűjteményben

A szabványos C++ -ban a gyűjtemény elemei közötti iteráció sok kódot igényel . Egyes nyelvek, például a C# , rendelkeznek olyan lehetőségekkel, amelyek " foreach " utasítást biztosítanak , amely automatikusan végigfut a gyűjtemény elemein az elejétől a végéig. A C++11 hasonló lehetőséget mutat be. A for utasítás megkönnyíti az iterációt az elemek gyűjteményén:

int my_array [ 5 ] = { 1 , 2 , 3 , 4 , 5 }; for ( int & x : my_array ) { x *= 2 ; }

Ez a for forma, amelyet angolul "range-based for"-nak hívnak, a gyűjtemény minden elemét meglátogatja. Ez vonatkozik a C tömbökre , inicializáló listákra és minden olyan típusra , amely funkcióval rendelkezik begin()és iterátorokatend() ad vissza . A szabványos könyvtár minden olyan tárolója , amely rendelkezik kezdet/vég párral, a gyűjtemény for utasításával fog működni.

Egy ilyen ciklus például C-szerű tömbökkel is működni fog, mert A C++11 mesterségesen vezeti be a számukra szükséges pszeudo-módszereket (kezdet, vége és néhány más).

// a klasszikus tömb tartomány alapú bejárása int arr1 [] = { 1 , 2 , 3 }; for ( auto el : arr1 ); Lambda függvények és kifejezések

A szabványos C++-ban például, amikor a szokásos C++ könyvtári algoritmusokat használjuk a sort and find , gyakran szükség van predikátum függvények meghatározására az algoritmus hívási helyének közelében. A nyelvben egyetlen mechanizmus létezik erre: a függvényosztály definiálása (a függvényen belül definiált osztály példányának átadása algoritmusoknak tilos (Meyers, Effective STL)). Ez a módszer gyakran túl redundáns és bőbeszédű, és csak megnehezíti a kód olvasását. Ráadásul a függvényekben definiált osztályokra vonatkozó szabványos C++ szabályok nem teszik lehetővé, hogy sablonokban használják őket, és így ellehetetlenítik a használatát.

A probléma kézenfekvő megoldása az volt, hogy lehetővé tették a lambda-kifejezések és a lambda-függvények meghatározását C++11-ben. A lambda függvény definíciója a következő:

[]( int x , int y ) { return x + y ; }

Ennek a névtelen függvénynek a visszatérési típusa decltype(x+y) . A visszatérési típus csak akkor hagyható el, ha a lambda függvény alakja . Ez a lambda függvény méretét egyetlen kifejezésre korlátozza. return expression

A visszatérési típus kifejezetten megadható, például:

[]( int x , int y ) -> int { int z = x + y ; visszatér z ; }

Ez a példa egy z ideiglenes változót hoz létre egy köztes érték tárolására. A normál funkciókhoz hasonlóan ez a köztes érték nem marad meg a hívások között.

A visszatérési típus teljesen elhagyható, ha a függvény nem ad vissza értéket (vagyis a visszatérési típus érvénytelen )

Lehetőség van a lambda függvénnyel azonos hatókörben meghatározott változókra való hivatkozások használatára is. Az ilyen változók halmazát általában zárásnak nevezik . A lezárások meghatározása és felhasználása a következők szerint történik:

std :: vektor < int > someList ; int összesen = 0 ; std :: for_each ( someList . begin (), someList . end (), [ & total ]( int x ) { összesen += x ; }); std :: cout << összesen ;

Ez megjeleníti a lista összes elemének összegét. A teljes változó a lambda-függvényzár részeként kerül tárolásra. Mivel a total veremváltozóra hivatkozik, megváltoztathatja az értékét.

A lokális változók záróváltozói a & hivatkozási szimbólum használata nélkül is megadhatók , ami azt jelenti, hogy a függvény átmásolja az értéket. Ez arra kényszeríti a felhasználót, hogy deklarálja a helyi változóra való hivatkozás vagy másolás szándékát.

A garantáltan hatókörükben végrehajtott lambda-függvényeknél lehetőség van az összes veremváltozó használatára anélkül, hogy kifejezetten hivatkozni kellene rájuk:

std :: vektor < int > someList ; int összesen = 0 ; std :: for_each ( someList . begin (), someList . end (), [ & ]( int x ) { összesen += x ; });

A megvalósítási módszerek belsőleg változhatnak, de a lambda-függvénytől elvárás, hogy egy mutatót tároljon annak a függvénynek a veremére, amelyben létrehozták, ahelyett, hogy egyedi veremváltozóhivatkozásokon működne.

Ha helyette [&]használja [=], akkor az összes használt változó átmásolódik, lehetővé téve a lambda függvény használatát az eredeti változókon kívül.

Az alapértelmezett átviteli mód az egyes változók listájával is kiegészíthető. Például, ha a legtöbb változót hivatkozással, egyet pedig érték szerint kell átadnia, használhatja a következő konstrukciót:

int összesen = 0 ; int érték = 5 ; [ & , érték ]( int x ) { összesen += ( x * érték ); } ( 1 ); //(1) hívja meg a lambda függvényt 1 értékkel

Ez azt eredményezi , hogy a teljes összeget referenciaként, az értéket pedig az érték szerint adja át.

Ha egy lambda függvény egy osztálymetódusban van definiálva, akkor azt az osztály barátjának tekintjük. Az ilyen lambda függvények hivatkozhatnak egy osztály típusú objektumra, és hozzáférhetnek annak belső mezőihez:

[]( SomeType * typePtr ) { typePtr -> SomePrivateMemberFunction (); }

Ez csak akkor működik, ha a lambda függvény hatóköre egy SomeType osztálymetódus .

Az aktuális metódussal kölcsönhatásba lépő objektum ezen mutatójával végzett munka speciális módon valósul meg. Ezt kifejezetten meg kell jelölni a lambda függvényben:

[ this ]() { this -> SomePrivateMemberFunction (); }

Egy űrlap [&]vagy [=]egy lambda függvény használatával ez automatikusan elérhetővé válik.

A lambda függvények típusa megvalósításfüggő; ennek a típusnak a neve csak a fordító számára elérhető. Ha egy lambda függvényt kell átadnia paraméterként, akkor annak sablon típusúnak kell lennie, vagy az std::function használatával kell tárolni . Az auto kulcsszó lehetővé teszi a lambda függvény helyi mentését:

auto myLambdaFunc = [ this ]() { this -> SomePrivateMemberFunction (); };

Ezenkívül, ha a függvény nem vesz fel argumentumokat, akkor ()kihagyhatja:

auto myLambdaFunc = []{ std :: cout << "hello" << std :: endl ; }; Alternatív függvény szintaxis

Néha szükség van egy függvénysablon megvalósítására, amely olyan kifejezést eredményez, amelynek ugyanolyan típusú és értékkategóriája van, mint bármely más kifejezésnek.

template < typename LHS , typename RHS > RETURN_TYPE AddingFunc ( const LHS & lhs , const RHS & rhs ) // mi legyen a RETURN_TYPE? { return lhs + rhs ; }

Annak érdekében, hogy az AddingFunc(x, y) kifejezés ugyanolyan típusú és értékkategóriájú legyen, mint az lhs + rhs kifejezés, ha adott x és y argumentum , a következő definíció használható a C++11-ben:

sablon < típusnév LHS , típusnév RHS > decltype ( std :: declval < const LHS &> () + std :: declval < const RHS &> ()) AddingFunc ( állandó LHS és lhs , konst RHS és jobb oldali ) { return lhs + rhs ; }

Ez a jelölés kissé körülményes, és jó lenne az lhs és az rhs használata az std::declval<const LHS &>() és az std::declval<const RHS &>() helyett. A következő verzióban azonban

template < typename LHS , typename RHS > decltype ( lhs + rhs ) AddingFunc ( const LHS & lhs , const RHS & rhs ) // Nem érvényes C++11 { return lhs + rhs ; }

ember által olvashatóbb, a decltype operandusban használt lhs és rhs azonosítók nem jelölhetik a később deklarált opciókat. A probléma megoldására a C++11 új szintaxist vezet be a függvények deklarálására, amelynek végén visszatérési típus van:

sablon < típusnév LHS , típusnév RHS > auto AddingFunc ( const LHS & lhs , const RHS & rhs ) -> decltype ( lhs + rhs ) { return lhs + rhs ; }

Meg kell azonban jegyezni, hogy az alábbi általánosabb AddingFunc megvalósításban az új szintaxis nem tesz jót a tömörségnek:

sablon < típusnév LHS , típusnév RHS > auto AddingFunc ( LHS && lhs , RHS && rhs ) -> decltype ( std :: előre < LHS > ( lhs ) + std :: előre < RHS > ( rhs )) { return std :: előre < LHS > ( lhs ) + std :: előre < RHS > ( rhs ); } sablon < típusnév LHS , típusnév RHS > auto AddingFunc ( LHS && lhs , RHS && rhs ) -> decltype ( std :: declval < LHS > () + std :: declval < RHS > ()) // ugyanaz a hatás, mint az std::forward fent { return std :: előre < LHS > ( lhs ) + std :: előre < RHS > ( rhs ); } sablon < típusnév LHS , típusnév RHS > decltype ( std :: declval < LHS > () + std :: declval < RHS > ()) // ugyanaz a hatás, mint a típus beírása a végére AddingFunc ( LHS && lhs , RHS && rhs ) { return std :: előre < LHS > ( lhs ) + std :: előre < RHS > ( rhs ); }

Az új szintaxis egyszerűbb deklarációkban és deklarációkban használható:

struct SomeStruct { auto FuncName ( int x , int y ) -> int ; }; auto SomeStruct :: FuncName ( int x , int y ) -> int { vissza x + y _ }

A " " kulcsszó autohasználata ebben az esetben csak a visszatérési típus késői jelzését jelenti, és nincs összefüggésben annak automatikus következtetésével.

Objektumkonstruktorok fejlesztése

A szabványos C++ nem teszi lehetővé, hogy egy osztálykonstruktort ugyanabban az osztályban egy másik konstruktorból hívjanak meg; minden konstruktornak teljesen inicializálnia kell az osztály összes tagját, vagy meg kell hívnia az osztály metódusait. Egy osztály nem állandó tagjai nem inicializálhatók azon a helyen, ahol ezeket a tagokat deklarálják.

A C++11 megszabadul ezektől a problémáktól.

Az új szabvány lehetővé teszi az egyik osztálykonstruktor meghívását egy másikból (az úgynevezett delegálás). Ez lehetővé teszi olyan konstruktorok írását, amelyek más konstruktorok viselkedését használják anélkül, hogy duplikált kódot vezetnének be.

Példa:

class SomeType { int szám ; nyilvános : SomeType ( int új_szám ) : szám ( új_szám ) {} SomeType () : SomeType ( 42 ) {} };

A példából látható, hogy az SomeTypeargumentumok nélküli konstruktor meghívja ugyanannak az osztálynak a konstruktorát egy egész argumentummal, hogy inicializálja a változót number. Hasonló hatás érhető el, ha ennek a változónak a deklarációjában 42-es kezdőértéket adunk meg.

class SomeType { int szám = 42 ; nyilvános : SomeType () {} explicit SomeType ( int új_szám ) : szám ( új_szám ) {} };

Bármely osztálykonstruktor 42-re inicializál number, ha maga nem rendel hozzá más értéket.

A Java , a C# és a D példák olyan nyelvekre, amelyek szintén megoldják ezeket a problémákat .

Megjegyzendő, hogy ha a C++03-ban egy objektumot teljesen létrejöttnek tekintünk, amikor a konstruktora befejezte a végrehajtást, akkor a C++11-ben legalább egy delegáló konstruktor végrehajtása után a többi konstruktor dolgozik teljesen felépített objektum. Ennek ellenére a származtatott osztály objektumai csak az alaposztályok összes konstruktorának végrehajtása után lesznek megszerkesztve.

A virtuális funkciók explicit helyettesítése és véglegessége

Lehetséges, hogy egy virtuális metódus aláírása megváltozott az alaposztályban, vagy kezdetben helytelenül lett beállítva a származtatott osztályban. Ilyen esetekben az adott metódus a származtatott osztályban nem írja felül a megfelelő metódust az alaposztályban. Tehát ha a programozó nem változtatja meg megfelelően a metódus aláírását az összes származtatott osztályban, akkor előfordulhat, hogy a metódus nem lesz megfelelően meghívva a program végrehajtása során. Például:

struct Base { virtual void some_func (); }; struct Származtatott : Base { void sone_func (); };

Itt egy származtatott osztályban deklarált virtuális függvény neve hibásan van írva, így az ilyen függvény nem írja felül a -t Base::some_func, és ezért nem hívja meg polimorf módon az alap alobjektumra mutató mutatón vagy hivatkozáson keresztül.

A C++11 lehetőséget ad ezeknek a problémáknak a fordítási időben történő nyomon követésére (a futási idő helyett). A visszamenőleges kompatibilitás érdekében ez a funkció opcionális. Az új szintaxis alább látható:

B szerkezet { virtual void some_func (); virtual void f ( int ); virtual void g () const ; }; D1 struktúra : nyilvános B { void sone_func () override ; // hiba: érvénytelen függvénynév void f ( int ) override ; // OK: felülírja ugyanazt a függvényt az alaposztályban virtual void f ( long ) override ; // hiba: paramétertípus hibás virtual void f ( int ) const override ; // hiba: function cv-qualification mismatch virtual int f ( int ) override ; // hiba: return type mismatch virtual void g () const final ; // OK: felülírja ugyanazt a függvényt az alaposztályban virtual void g ( long ); // OK: új virtuális függvény }; struktúra D2 : D1 { virtual void g () const ; // hiba: kísérlet a végső függvény lecserélésére };

A virtuális függvény specifikációjának jelenléte finalazt jelenti, hogy a további cseréje lehetetlen. Ezenkívül a végső specifikátorral definiált osztály nem használható alaposztályként:

struct F final { int x , y ; }; struct D : F // hiba: a végső osztályokból való öröklés nem megengedett { int z ; };

A overrideés azonosítóknak finalcsak bizonyos helyzetekben van különleges jelentése. Más esetekben normál azonosítóként használhatók (például egy változó vagy függvény neveként).

Null pointer állandó

A C 1972-es megjelenése óta a konstans 0 egy egész szám és egy nullamutató kettős szerepét tölti be. A C nyelvben rejlő kétértelműség kezelésének egyik módja a makró NULL, amely jellemzően a ((void*)0)vagy helyettesítést hajtja végre 0. A C++ ebben a tekintetben különbözik a C-től, és csak 0egy nulla mutató használatát teszi lehetővé állandóként. Ez rossz interakcióhoz vezet a funkció túlterhelésével:

void foo ( char * ); void foo ( int );

Ha a makró NULLa következőképpen van definiálva 0(ami gyakori a C++-ban), akkor a sor foo(NULL);hívást fog eredményezni foo(int), nem foo(char *)pedig úgy, ahogy azt a kód gyors áttekintése sugallja, ami szinte biztosan nem a programozó szándéka.

A C++11 egyik újdonsága egy új kulcsszó a null pointer állandó leírására - nullptr. Ez a konstans típusú std::nullptr_t, amely implicit módon konvertálható bármely mutató típusává, és összehasonlítható bármely mutatóval. Az implicit átalakítás integrált típusba nem megengedett, kivéve a bool. A szabvány eredeti javaslata nem tette lehetővé a logikai értékre való implicit konverziót, de a szabványos szerkesztési csoport a hagyományos mutatótípusokkal való kompatibilitás érdekében engedélyezte az ilyen átalakításokat. A javasolt megfogalmazást 2008 júniusában egyhangú szavazással módosították [1] .

A visszafelé kompatibilitás érdekében a konstans 0nullmutatóként is használható.

char * pc = nullptr ; // igaz int * pi = nullptr ; // true bool b = nullptr ; // jobb. b=hamis. int i = nullptr ; // hiba foo ( nullptr ); // hívja a foo(char *), nem a foo(int);

Gyakran azok a konstrukciók, ahol a mutató garantáltan üres, egyszerűbbek és biztonságosabbak, mint a többi – így túlterhelheti a -t . nullptr_t

osztály hasznos teher ; class SmartPtr { SmartPtr () = alapértelmezett ; SmartPtr ( nullptr_t ) {} // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< explicit SmartPtr ( hasznos terhelés * aData ) : fData ( aData ) {} // konstruktorok és op= másolása ~ SmartPtr () { delete fData ; } privát : Hasznos teher * fData = nullptr ; } SmartPtr getPayload1 () { return nullptr ; } // A SmartPtr(nullptr_t) túlterhelés meghívásra kerül. Erősen gépelt enumok

A szabványos C++-ban az enumok nem típusbiztosak. Valójában egész számokkal ábrázolják őket, annak ellenére, hogy maguk a felsorolások típusai különböznek egymástól. Ez lehetővé teszi a különböző enumokból származó két érték összehasonlítását. Az egyetlen lehetőség, amit a C++03 kínál az enumok védelmére, az az, hogy nem konvertálja implicit módon egy enum egész számát vagy elemeit egy másik enum elemeivé. Ezenkívül a memóriában való megjelenítése (egész típus) megvalósításfüggő, ezért nem hordozható. Végül a felsorolási elemeknek közös a hatóköre, ami lehetetlenné teszi az azonos nevű elemek létrehozását különböző felsorolásban.

A C++11 ezeknek az enumoknak egy speciális osztályozását kínálja, a fenti hátrányoktól mentesen. Az ilyen felsorolások leírására deklarációt használnak (ezt szinonimájaként enum classis használhatjuk ):enum struct

enum class felsorolás { Val1 , Val2 , Val3 = 100 , Val4 , /* = 101 */ };

Az ilyen felsorolás típusbiztos. Az osztály enum elemei nem konvertálhatók implicit egész számokká. Ennek következtében az egész számokkal való összehasonlítás sem lehetséges (a kifejezés Enumeration::Val4 == 101fordítási hibát eredményez).

Az osztályfelsorolás típusa mostantól független a megvalósítástól. Alapértelmezés szerint, mint a fenti esetben, ez a típus int, de más esetekben a típus manuálisan állítható be az alábbiak szerint:

enum class Enum2 : unsigned int { Val1 , Val2 };

Az enum tagok körét az enum név köre határozza meg. Az elemnevek használatához meg kell adni az osztály enum nevét. Tehát például az érték Enum2::Val1meg van határozva, de az érték Val1 nincs megadva.

Ezenkívül a C++11 lehetőséget kínál a hatókör és az alapul szolgáló típusok kifejezett meghatározására a normál enumokhoz:

enum Enum3 : előjel nélküli hosszú { Val1 = 1 , Val2 };

Ebben a példában az enum elemnevek az enum térben vannak definiálva (Enum3::Val1), de a visszafelé kompatibilitás érdekében az elemnevek a közös hatókörben is elérhetők.

A C++11-ben is lehetséges az enumok előre deklarálása. A C++ korábbi verzióiban ez nem volt lehetséges, mert egy enum mérete az elemeitől függött. Az ilyen nyilatkozatok csak akkor használhatók, ha a felsorolás mérete (kifejezetten vagy implicit módon) meg van adva:

enum Enum1 ; // érvénytelen C++ és C++11 esetén; mögöttes típus nem határozható meg enum Enum2 : unsigned int ; // igaz a C++11-re, az alapul szolgáló típus kifejezetten meghatározott enum osztály Enum3 ; // igaz a C++11-re, az alapul szolgáló típus int enum osztály Enum4 : unsigned int ; // igaz a C++11-re. enum Enum2 : unsigned short ; // érvénytelen a C++11 esetében, mert az Enum2 korábban más mögöttes típussal volt deklarálva Szögzárójelek

A szabványos C++ elemzők mindig a ">>" karakterkombinációt határozzák meg jobb shift operátorként. A sablonparaméterekben (ha be vannak ágyazva) a záró szögletes zárójelek közötti szóköz hiánya szintaktikai hibaként kezelendő.

A C++11 ebben az esetben javítja az értelmező viselkedését, így a több derékszögű zárójelet a rendszer a sablon argumentumlistáinak lezáróként értelmezi.

A leírt viselkedés zárójelekkel rögzíthető a régi megközelítés javára.

sablon < osztály T > osztály Y { /* ... */ }; Y < X < 1 >> x3 ; // Helyes, ugyanaz, mint "Y<X<1> > x3;". I < X < 6 >> 1 >> x4 ; // Szintaktikai hiba. Be kell írnia, hogy "Y<X<(6>>1)>> x4;".

Mint fentebb látható, ez a változtatás nem teljesen kompatibilis az előző szabvánnyal.

Explicit konverziós operátorok

A C++ szabvány a kulcsszót explicitmódosítóként biztosítja az egyparaméteres konstruktorokhoz, így az ilyen konstruktorok nem működnek implicit konverziós konstruktorként. Ez azonban semmilyen módon nem érinti a tényleges konverziós operátorokat. Például egy intelligens mutató osztály tartalmazhat operator bool()egy normál mutatót utánzót. Egy ilyen operátor például így hívható: if(smart_ptr_variable)(az ág akkor kerül végrehajtásra, ha a mutató nem nulla). A probléma az, hogy egy ilyen operátor nem véd más váratlan átalakítások ellen. Mivel a típus boolaritmetikai típusként van deklarálva a C++-ban, lehetséges az implicit konverzió bármilyen egész típusra vagy akár lebegőpontos típusra, ami viszont váratlan matematikai műveletekhez vezethet.

A C++11 nyelvben a kulcsszó explicita konverziós operátorokra is vonatkozik. A konstruktorokhoz hasonlóan véd a váratlan implicit konverziók ellen. Azok a helyzetek azonban, amikor a nyelv kontextus szerint logikai típust vár (például feltételes kifejezésekben, ciklusokban és logikai operátor-operandusokban), explicit konverziónak minősülnek, és az explicit logikai konverziós operátort közvetlenül hívják meg.

Sablon typedef

A szabványos C++-ban egy kulcsszó typedefcsak egy másik típus szinonimájaként használható, ideértve a sablonspecifikáció szinonimájaként az összes paramétert megadva. De nem lehet sablon szinonimát létrehozni. Például:

sablon < típusnév Első , típusnév Második , int harmadik > osztály SomeType ; sablon < typenameSecond > _ typedef SomeType < OtherType , Second , 5 > TypedefName ; // C++-ban nem lehetséges

Ez nem fordítódik le.

A C++11 hozzáadta ezt a képességet a következő szintaxissal:

sablon < típusnév Első , típusnév Második , int harmadik > osztály SomeType ; sablon < typenameSecond > _ using TypedefName = SomeType < OtherType , Second , 5 > ;

A C++11 nyelvben az irányelv usingadattípusként is használható.

typedef void ( * OtherType )( double ); // Régi stílus az OtherType használatával = void ( * )( double ); // Új szintaxis Korlátozások eltávolítása a szakszervezetből

A korábbi C++ szabványokban számos korlátozás vonatkozik az osztálytípusok tagjainak szakszervezeteken belüli használatára. Az uniók különösen nem tartalmazhatnak nem triviális konstruktorral rendelkező objektumokat. A C++11 eltávolít néhány korlátozást. [2]

Íme egy egyszerű példa a C++11-ben engedélyezett csatlakozásra:

//az elhelyezéshez new #include <new> structPoint { _ Pont () {} Pont ( int x , int y ) : x_ ( x ), y_ ( y ) {} int x_ , y_ ; }; szakszervezet U { int z ; dupla w ; pont p ; // Nem igaz a C++03-ra, mert a Pointnak van egy nem triviális konstruktora. A kód azonban megfelelően működik C++11-ben. U () { new ( & p ) Pont (); } // Nincsenek nem triviális módszerek az unióhoz. // Ha szükséges, eltávolíthatók, hogy a kézi definíció működjön };

A változtatások nem érintik a meglévő kódot, mivel csak a meglévő korlátozásokat lazítják.

A funkcionalitás kiterjesztése

Ez a rész olyan új szolgáltatásokat ismertet, amelyek korábban nem voltak elérhetők, vagy speciális, nem hordozható könyvtárakat igényeltek.

Változó argumentum sablonok

A C++11 előtt a sablonok (osztályok vagy függvények) csak meghatározott számú argumentumot vehettek fel, amelyeket akkor határoztak meg, amikor a sablont eredetileg deklarálták. A C++11 lehetővé teszi, hogy változó számú, bármilyen típusú argumentumot tartalmazó sablonokat definiáljunk.

sablon < típusnév ... Értékek > osztály tuple ;

Például a sablon osztály tuple ( tuple ) tetszőleges számú típusnevet fogad el sablonparaméterként:

osztály tuple < int , std :: vektor < int > , std :: térkép < std :: string , std :: vektor < int >>> valamilyen_példánynév ;

Az érvek hiányozhatnak, így az opció class tuple<> some_instance_nameis működni fog.

A sablonok argumentumok nélküli példányosításának megakadályozására a következő definíció használható:

template < typename First , typename ... Rest > class tuple ;

A változó argumentumú sablonok függvényekre is alkalmazhatók, lehetővé téve a variadic függvények típusbiztos változataiban (például printf) és nem triviális objektumok kezelésében való használatát.

template < typename ... Params > void printf ( const std :: string & str_format , Params ... paraméterek );

A ... operátor itt két szerepet tölt be. A Paramstól balra egy operátor bejelenti, hogy be kell csomagolni a paramétereket. A csomagolt paraméterek használatával 0 vagy több argumentum társítható egy sablonhoz. A csomagolt paraméterek nem csak típusnevek átadására használhatók. A jobb oldali ... operátor pedig külön argumentumokba csomagolja ki a paramétereket (lásd args...az alábbi példában a függvény törzsét).

Lehetőség van változó számú argumentumú sablonok rekurzív használatára is. Egy példa erre a printf típusbiztos helyettesítése :

void printf ( const char * s ) { míg ( * s ) { if ( * s == '%' && * ( ++ s ) != '%' ) throw std :: runtime_error ( "invalid format string: hiányzó argumentumok" ); std :: cout << * s ++ ; } } sablon < típusnév T , típusnév ... Args > void printf ( const char * s , T érték , Args ... args ) { míg ( * s ) { if ( * s == '%' && * ( ++ s ) != '%' ) { std :: cout << érték ; ++ s ; printf ( s , args ...); // az argumentumok feldolgozásának folytatása akkor is, ha *s == 0 return ; } std :: cout << * s ++ ; } throw std :: logic_error ( "extra argumentumok a printf-hez" ); }

Ez a minta rekurzív. Ne feledje, hogy a printf függvény meghívja a példányosítás eredményeit vagy az alap printf függvényt, ha az args... üres.

Nincs egyszerű módja a paraméterek megkerülésének egy változó sablonban. Ennek ellenére a kicsomagolási operátor argumentumának használata megkerüli ezt a problémát.

Például egy osztály a következőképpen definiálható:

template < typename ... BaseClasses > class ClassName : public BaseClasses ... { nyilvános : Osztálynév ( BaseClasses && ... base_classes ) : BaseClasses ( base_classes )... {} };

A kicsomagoló operátor minden típusú szülőosztályt lemásol ClassNameoly módon, hogy az osztály a sablonparaméterekben megadott összes típusból öröklődik. Ezenkívül a konstruktornak el kell fogadnia az összes alaposztályra való hivatkozást, hogy minden szülő alaposztály inicializálva legyen ClassName.

A sablon paraméterei átirányíthatók. Az rvalue hivatkozásokkal kombinálva (lásd fent), átirányíthatja:

template < typename TypeToConstruct > struct SharedPtrAllocator { template < typename ... Args > std :: shared_ptr < TypeToConstruct > construct_with_shared_ptr ( Args && ... params ) { return std :: shared_ptr < TypeToConstruct > ( new TypeToConstruct ( std :: forward < Args > ( params )...)); }; };

Ez a kód kicsomagolja az argumentumlistát a TypeToConstruct konstruktorba. A szintaxis std::forward<Args>(params)lehetővé teszi az argumentumok abszolút átlátható átirányítását a konstruktorhoz, függetlenül azok rérték természetétől. A funkció automatikusan becsomagolja a mutatókat, std::shared_ptrhogy védelmet nyújtson a memóriaszivárgás ellen.

A csomagolt argumentumok számát is megadhatja a következőképpen:

template < típusnév ... Args > struct SomeStruct { static const int size = sizeof ...( Args ); };

Itt SomeStruct<Type1, Type2>::sizeegyenlő 2, és SomeStruct<>::sizeegyenlő 0.

Új karakterlánc-literálok

A C++03 kétféle karakterlánc-literált kínált. Az első típus, egy dupla idézőjeles karakterlánc, egy null-végződésű tömb típusú const char. A második típus, amelyet ként definiálunk L"", egy null-végződésű tömb típusú tömb const wchar_t, ahol wchar_tegy széles, határozatlan méretű és szemantikai karakter. A literáltípusok egyike sem támogatja az UTF-8 , UTF-16 karakterlánc-literálokat vagy bármely más típusú Unicode kódolást

A típusdefiníciót charúgy módosították, hogy kifejezetten azt mondja, hogy legalább akkora, mint egy nyolcbites UTF-8 kódolás tárolásához , és elég nagy ahhoz, hogy bármilyen karaktert tartalmazzon a futásidejű karakterkészletben. Korábban a szabványban ezt a típust egyetlen karakterként határozták meg, később a C nyelvi szabványt követve garantálttá vált, hogy legalább 8 bitet foglaljon el.

A C++11 szabvány három Unicode kódolást támogat: UTF-8 , UTF-16 és UTF-32 . A beépített karaktertípus fenti módosításai mellett a charC++11 két új karaktertípust ad hozzá: char16_tés char32_t. Úgy tervezték, hogy UTF-16, illetve UTF-32 karaktereket tároljanak.

Az alábbiakban bemutatjuk, hogyan lehet karakterlánc-literálokat létrehozni az egyes kódolásokhoz:

u8 "UTF-8 karakterlánc vagyok." u "Ez egy UTF-16 karakterlánc." U "Ez egy UTF-32 karakterlánc."

Az első sor típusa normál const char[]. A második sor típusa const char16_t[]. A harmadik sor típusa const char32_t[].

Amikor karakterlánc-literálokat készítünk a Unicode szabványban, gyakran hasznos, ha a Unicode kódot közvetlenül a karakterláncba illesztjük be. A C++11 a következő szintaxist biztosítja ehhez:

u8 "Ez egy Unicode karakter: \u2018 ." u "Ez egy nagyobb Unicode karakter: \u2018 ." U "Ez egy Unicode karakter: \U00002018 ."

Az utána lévő számnak \uhexadecimálisnak kell lennie; nem szükséges az előtagot használni 0x. Az azonosító \uegy 16 bites Unicode kódot jelent; 32 bites kód megadásához \U32 bites hexadecimális számot is használunk. Csak érvényes Unicode kódok adhatók meg. Például az U+D800-U+DFFF tartományba eső kódok nem engedélyezettek, mert az UTF-16 helyettesítő párok számára vannak fenntartva.

Néha hasznos lehet elkerülni a karakterláncok kézi kihagyását, különösen XML -fájlliterálok, szkriptnyelvek vagy reguláris kifejezések használatakor. Ebből a célból a C++11 támogatja a "nyers" karakterlánc-literálokat:

R"(The String Data \ Stuff " )" R"határoló (The String Data \ Stuff " )határoló"

Az első esetben a "(és között minden )"a karakterlánc része. A karaktereket "és \nem kell megszökni. A második esetben "delimiter(egy karakterláncot kezd, és csak akkor ér véget, amikor eléri a )delimiter". A karakterlánc delimiterlehet bármilyen, legfeljebb 16 karakter hosszúságú karakterlánc, beleértve az üres karakterláncot is. Ez a karakterlánc nem tartalmazhat szóközt, vezérlőkaraktereket, " (", " )" vagy a " \" karaktert. Ennek a határoló karakterláncnak a használata lehetővé teszi a " )" karakter használatát a nyers karakterlánc-literálokban. Például R"delimiter((a-z))delimiter"egyenértékű a "(a-z)"[3]-mal .

A "nyers" karakterlánc-literálok kombinálhatók kibővített literálkészlettel (előtag L"") vagy bármilyen Unicode literál előtaggal.

LR"(Nyers széles karakterlánc literál \t (tabulátor nélkül)" u8R"XXX("Nyers UTF-8" karakterlánc vagyok.)XXX" uR"*(Ez egy "nyers UTF-16" karakterlánc.)*" UR"(Ez egy "nyers UTF-32" karakterlánc.)" Egyéni literálok

Az egyéni literálok az operátor túlterhelésével valósulnak meg operator"". A literálok lehetnek inline vagy constexpr minősítők . Kívánatos, hogy a szó szerinti szöveg aláhúzással kezdődjön, mivel ez ütközhet a jövőbeli szabványokkal. Például az i literál már a -ból származó komplex számokhoz tartozik std::complex.

A literálok csak az alábbi típusok egyikét vehetik fel: const char * , unsigned long long int , long double , char , wchar_t , char16_t , char32_t. Elegendő csak a const char * típusnál túlterhelni a literált . Ha nem talál megfelelőbb jelöltet, akkor egy ilyen típusú operátort hívunk meg. Példa a mérföldek kilométerre konvertálására:

constexpr int operátor "" _mi ( unsigned long long int i ) { return 1.6 * i ;}

A karakterlánc-literáloknak van egy második argumentuma std::size_t, és az egyik az első: const char * , const wchar_t *, const char16_t * , const char32_t *. A karakterlánc-literálok a dupla idézőjelbe tett bejegyzésekre vonatkoznak.

Többszálú memóriamodell

A C++11 szabványosítja a többszálú programozás támogatását. Két részről van szó: egy memóriamodellről, amely lehetővé teszi több szál egyidejű létezését egy programban, és egy könyvtárat, amely támogatja a szálak közötti kommunikációt.

A memóriamodell meghatározza, hogy több szál hogyan férhet hozzá ugyanahhoz a memóriahelyhez, és meghatározza, hogy az egyik szál változtatásai mikor válnak láthatóvá a többi szál számára.

Menetes tároló Explicit alapértelmezett és speciális metódusok eltávolítása

Specifikátorok defaultés deletea metódustörzs helyett megadhatók.

osztály Foo { nyilvános : foo () = alapértelmezett ; Foo ( int x ) { /* ... */ } };

A specifikátor defaultaz alapértelmezett megvalósítást jelenti, és csak speciális tagfüggvényekre alkalmazható:

  • alapértelmezett konstruktor;
  • másolat konstruktor;
  • mozgatni konstruktort;
  • hozzárendelés operátor;
  • mozgatható operátor;
  • pusztító.

A deletespecifikátor megjelöli azokat a metódusokat, amelyekkel nem lehet dolgozni. Korábban az ilyen konstruktorokat deklarálni kellett az osztály privát hatókörében.

osztály Foo { nyilvános : foo () = alapértelmezett ; Foo ( const Foo & ) = törlés ; void bar ( int ) = törlés ; üres sáv ( dupla ) {} }; // ... Foo obj ; obj . bár ( 5 ); // hiba! obj . bár ( 5,42 ); // rendben Írja be long long int

Az egész típus a C99long long int -ben van megadva, és de facto széles körben használják a C++-ban. Most már hivatalosan is szerepel a szabványban.

Statikus diagnosztika

A C++11 két statikus diagnosztikai mechanizmussal rendelkezik:

  • A kulcsszó static_assertfordítási hibát jelez, ha a zárójelben szereplő kifejezés hamis.
  • Sablonokat tartalmazó könyvtár type_traits, amely fordításkor típusinformációkat biztosít.
#include <type_traits> sablon < classT > _ üres futás ( T * aData , méret_t n ) { static_assert ( std :: is_pod < T >:: value , "A T típusnak egyszerűnek kell lennie." ); ... } Az osztályokban lévő adattagok mérete objektum létrehozása nélkül

A C++03 lehetővé tette az operátor sizeofhasználatát egyszerű típusokon és objektumokon. De a következő konstrukció érvénytelen volt:

struct SomeType { OtherType tag ; }; sizeof ( SomeType :: tag ); //C++03-ban nem működik, C++11-ben viszont igaz.

A hívás eredménye egy méret legyen OtherType. A C++03 nem támogatja az ilyen hívást, és ez a kód nem fordul le. A C++11 lehetővé teszi az ilyen konstrukciókat.

Objektum igazítási vezérlés és igazítási kérések

A C++11 lehetővé teszi a változók igazítását a alignofés operátorok használatával alignas.

alignoffelvesz egy típust, és visszaadja a bájtok számát, amennyivel az objektum eltolható. Például struct X { int n; char c; };8 bájt esetén alignofa 4 értéket adja vissza. Hivatkozások esetén a hivatkozástípus értékét adja vissza; tömbök esetén a tömbelem értéke

alignasvezérli egy objektum igazítását a memóriában. Például megadhatja, hogy a char tömböt megfelelően igazítani kell a típus tárolásához float:

alignas ( float ) unsigned char c [ sizeof ( float )] Megvalósítások engedélyezése szemétgyűjtővel Attribútumok

Változások a C++ Standard Library-ban

Meglévő komponensek módosításai

  • Beillesztéskor std::seta programozó néha tudja, hogy az új elem milyen pozícióba kerül. Ehhez egy opcionális paramétert használnak - "hint"; ha a feltételezés helyes, az időbecslés egy amortizált állandó lesz, nem pedig az O(log n) . A C++11-ben a "hint" jelentése megváltozott: korábban az aktuális előtti elemet jelentette , ami nem teljesen helyes: nem világos, mit kell tenni, ha a beillesztés az első helyen van. Most ez az elem az aktuális után .
  • Egy kényelmes sablont írtak, amely memóriafoglalás nélkül hívja meg a konstruktorokat - std::allocator_traits<>::construct(). Minden tárolóhoz hozzáadtak egy metódust emplace, amely egy objektumot hoz létre a helyén.
  • Új C++11 nyelvi funkciók hozzáadva.
  • Hozzáadott metódusok cbeginés cendgarantált const iterátorok létrehozása. Kényelmes metaprogramozáshoz, típusok beállításához a -n keresztül auto.
  • Azokban a tárolókban, amelyek margóval indítják a memóriát, megjelent egy függvény shrink_to_fit.
  • B std::listszigorúbb korlátokat szab arra vonatkozóan, hogy mit kell tenni O ( n ), és mit kell tenni az állandó időben.
  • std::vectorKözvetlen memória-hozzáférés hozzáadva a következőn keresztül data().
  • Többek tiltása std::string, hogy ugyanarra a memóriára hivatkozzanak. Ennek köszönhetően megjelent a közvetlen hozzáférés a -n keresztül front(), ami kényelmes például a string és a WinAPI interakciójához .

Flow control

Míg a C++03 nyelv olyan memóriamodellt biztosít, amely támogatja a többszálú feldolgozást, a többszálú használat tényleges használatához a fő támogatást a C++11 szabványkönyvtár biztosítja.

Egy szálosztály ( std::thread) van megadva, amely elfogad egy függvényobjektumot (és a neki átadandó argumentumok opcionális listáját) az új szálon való futtatáshoz. Kényszerítheti a szál leállítását egy másik végrehajtó szál befejezése előtt, ha támogatja a szálak összevonását egy tagfüggvényen keresztül std::thread::join(). Ha lehetséges, a tagfüggvényen keresztül elérhető a szál natív leírója a platform-specifikus műveletekhez std::thread::native_handle().

A szálak közötti szinkronizáláshoz megfelelő mutexet ( std::mutex, std::recursive_mutexstb.) és feltételváltozókat ( std::condition_variableés std::condition_variable_any) adunk hozzá a könyvtárhoz. Erőforrás-inicializálási (RAII) zárakon ( std::lock_guardés std::unique_lock) és zárolási algoritmusokon keresztül érhetők el a könnyű használat érdekében.

A nagy teljesítményű, alacsony szintű munka néha megköveteli a kommunikációt a szálak között anélkül, hogy mutexek többletterhelése lenne. Ez a memóriahelyeken végzett atomi műveletekkel történik. Opcionálisan megadhatják a művelethez szükséges minimális memória láthatósági korlátokat. Explicit memóriakorlátok is használhatók erre a célra.

A C++11 szálkönyvtár határidőket és ígéreteket is tartalmaz az aszinkron eredmények szálak közötti átadására, valamint egy olyan osztályt std::packaged_task, amely egy ilyen aszinkron eredményt generáló függvényhívás burkolására szolgál. A határidős javaslatot kritizálták, mivel hiányzik belőle a határidős ügyletek kombinálásának módja és egyetlen ígéret teljesülésének ellenőrzése az ígéretek sorozatában.

További magas szintű befűzési lehetőségeket, például szálkészleteket helyeztek el egy jövőbeni C++ fehér papírban. Nem részei a C++11-nek, de végső megvalósításuk várhatóan teljes egészében a szálfűzési könyvtár funkcióira épül.

Az új funkció std::asynckényelmes módot biztosít a feladatok futtatására és a végrehajtásuk eredményének a std::future. A felhasználó kiválaszthatja, hogy a job aszinkron módon fusson egy külön szálon, vagy szinkronban az aktuális szálon, és várja az értéket.

Hash táblázatok

std::hash_setés std::hash_maprégóta nem szabványos STL-kiterjesztések, valójában a legtöbb fordítóprogramban implementálva vannak. C++11-ben szabványossá váltak, std::unordered_setés néven std::unordered_map. Bár valójában hash táblákról van szó, és a szabvány nem hagy nagy mozgásteret, a neveket C++ stílusban adják: nem "hogyan vannak implementálva", hanem "mik azok".

Reguláris kifejezések

A fejlécfájlban deklarált új könyvtár <regex>több új osztályt tartalmaz:

A funkciót std::regex_searcha keresésre, a 'keresni és cserélni' műveletre a függvényt használjuk std::regex_replace. A függvény a csere végrehajtása után egy karakterláncot ad vissza. std::regex_searchA és algoritmusok std::regex_replaceegy reguláris kifejezést és egy karakterláncot vesznek be bemenetként, és a talált eredményeket a példány példányaként adják vissza std::match_results.

Használati példa std::match_results:

const char * reg_esp = "[ ,. \\ t \\ n;:]" ; // Elválasztó karakterek listája. // ugyanez megtehető "raw" karakterláncok használatával: // const char *reg_esp = R"([ ,.\t\n;:])"; std :: regex rgx ( reg_esp ); // A 'regex' a 'char' sablonparaméterrel rendelkező 'basic_regex' sablonosztály egy példánya . std :: cmatch match ; // A 'cmatch' a 'match_results' sablon osztály egy példánya, 'const char *' sablonparaméterrel. const char * target = "Láthatatlan egyetem - Ankh-Morpork" ; // Javítja a 'target' karakterlánc összes szavát a 'reg_esp' karakterekkel elválasztva. if ( std :: regex_search ( cél , egyezés , rgx ) ) { // Ha az adott karakterekkel elválasztott szavak jelen vannak a karakterláncban. const size_t n = egyezés . méret (); for ( méret_t a = 0 ; a < n ; a ++ ) { std :: string str ( match [ a ]. first , match [ a ]. second ); std :: cout << str << " \n " ; } }

Ne feledje, hogy dupla fordított perjelre van szükség, mert a C++ fordított perjelet használ a karakterek kilépésére. Használhat "nyers karakterláncokat" - a C++11 szabvány másik újítását.

A könyvtár <regex>nem igényli a meglévő fejlécfájlok módosítását, sem további nyelvi kiterjesztések telepítését.


Bővíthető véletlenszám-generálási osztályok

A C szabványos könyvtár lehetővé tette pszeudo-véletlen számok generálását a rand. A viselkedése azonban a megvalósítástól függően változhat.

Ez a funkcionalitás két részre oszlik: a generátormotorra, amely a véletlenszám-generátor aktuális állapotát tartalmazza és pszeudo-véletlen számokat állít elő, valamint az eloszlásra, amely meghatározza az eredmény tartományát és matematikai eloszlását . E két objektum kombinációja véletlenszám-generátort hoz létre.

Generátor motorok:

Elosztások:

Példa:

#include <random> #include <funkcionális> std :: egységes_int_eloszlás < int > eloszlás ( 0 , 99 ); std :: mt19937motor ; _ // Mersenne vortex MT19937 auto generator = std :: bind ( elosztás , motor ); int véletlen = generátor (); // Véletlenszerű szám 0 és 99 között. int random2 = eloszlás ( motor ); // Szerezzen be egy véletlen számot közvetlenül a motor és az elosztás használatával.



A szabványban nem szereplő tervezett funkciók

Modulok A fejlécfájlok hatalmas mennyisége a fordítási idő négyzetes megnövekedéséhez vezetett: a kód mennyisége és a modulok száma is megnő egyetlen fordítási egységben. A moduloknak a Delphi DCU-fájlokhoz vagy a Java osztályfájlokhoz hasonló mechanizmust kell biztosítaniuk .

Eltávolított vagy elavult funkciók

Lásd még

Jegyzetek

  1. Herb Sutter , Nemzetközi szabványunk van: a C++0x egyhangúlag jóváhagyva Archiválva : 2018. december 11. a Wayback Machine -nél
  2. Scott Meyers , Összefoglaló a C++11 szolgáltatás elérhetőségéről a gcc-ben és az MSVC -ben Archiválva : 2011. október 26. a Wayback Machine -nél , 2011. augusztus 16.
  3. ISO , ISO/IEC 14882:2011 Archiválva : 2013. január 29. a Wayback Machine -nél
  4. ↑ C++0x név az N3290 végleges tervezetében definiálva. Archiválva : 2010. június 20. a Wayback Machine -nél
  5. Stroustrup, Bjorn  – C++0x – a következő ISO C++ szabvány Archiválva : 2011. május 11. a Wayback Machine -nél
  6. C++ Standards Committee Papers . Letöltve: 2008. február 24. Az eredetiből archiválva : 2010. március 18..
  7. A C++ forrás Bjarne Stroustrup ( 2006. január 2. ) Rövid áttekintés a C++0x-ról . (Angol)

A C++ Szabványügyi Bizottság dokumentumai

  •   dok. sz. 1401: Jan Kristoffersen (2002. október 21.)Atomműveletek többszálú környezetekkel
  •   dok. sz. 1402: Doug Gregor (2002. október 22.)Javaslat egy polimorf függvényobjektum burkoló hozzáadására a szabványos könyvtárhoz
  •   dok. sz. 1403: Doug Gregor (2002. november 8.)Javaslat sortípusok hozzáadására a szabványos könyvtárba
  •   dok. sz. 1424: John Maddock (2003. március 3.)Javaslat a típusjellemzők hozzáadására a szabványos könyvtárhoz
  •   dok. sz. 1429: John Maddock (2003. március 3.)Javaslat a reguláris kifejezés hozzáadására a szabványos könyvtárhoz
  •   dok. sz. 1449: B. Stroustrup, G. Dos Reis, Mat Marcus, Walter E. Brown, Herb Sutter (2003. április 7.)Javaslat sablon álnevek hozzáadására a C++ nyelven
  •   dok. sz. 1450: P. Dimov, B. Dawes, G. Colvin (2003. március 27.)Javaslat általános célú intelligens mutatók hozzáadására a könyvtári műszaki jelentéshez (1. változat)
  •   dok. sz. 1452: Jens Maurer (2003. április 10.)Javaslat egy bővíthető véletlenszám-szolgáltatás hozzáadására a szabványos könyvtárhoz (2. változat)
  •   dok. sz. 1453: D. Gregor, P. Dimov (2003. április 9.)Javaslat egy referenciaburkoló hozzáadására a szabványos könyvtárhoz (1. változat)
  •   dok. sz. 1454: Douglas Gregor, P. Dimov (2003. április 9.)Egységes módszer a függvényobjektum-visszatérési típusok kiszámítására (1. változat)
  •   dok. sz. 1456: Matthew Austern (2003. április 9.)Javaslat hash-táblázatok hozzáadására a szabványos könyvtárhoz (4. változat)
  •   dok. sz. 1471: Daveed Vandevoorde (2003. április 18.) ReflexiveMetaprograming C++ nyelven
  •   dok. sz. 1676: Bronek Kozicki (2004. szeptember 9.)Nem tag túlterhelt másolási megbízás operátor
  •   dok. sz. 1704: Douglas Gregor, Jaakko Järvi, Gary Powell (2004. szeptember 10.)Variadic Templates: Exploring the Design Space
  •   dok. sz. 1705: J. Järvi, B. Stroustrup, D. Gregor, J. Siek, G. Dos Reis (2004. szeptember 12.)Decltype (és auto)
  •   dok. sz. 1717: Francis Glassborow, Lois Goldthwaite (2004. november 5.)explicit osztály- és alapértelmezett meghatározások
  •   dok. sz. 1719: Herb Sutter, David E. Miller (2004. október 21.)Erősen beírt enumok (1. változat)
  •   dok. sz. 1720: R. Klarer, J. Maddock, B. Dawes, H. Hinnant (2004. október 20.)Javaslat statikus állítások hozzáadására az alapnyelvhez (3. változat)
  •   dok. sz. 1757: Daveed Vandevoorde (2005. január 14.)Derékszögű zárójelek (2. változat)
  •   dok. sz. 1811: J. Stephen Adamczyk (2005. április 29.)A hosszú hosszú típus hozzáadása a C++-hoz (3. változat)
  •   dok. sz. 1815: Lawrence Crowl (2005. május 2.)ISO C++ stratégiai terv a többszálú használathoz
  •   dok. sz. 1827: Chris Uzdavinis, Alisdair Meredith (2005. augusztus 29.)Explicit Override Syntax for C++
  •   dok. sz. 1834: Detlef Vollmann (2005. június 24.)Könyörgés a C++ ésszerű párhuzamos feldolgozás támogatásáért
  •   dok. sz. 1836: ISO/IEC DTR 19768 (2005. június 24.)A C++ könyvtárbővítésekről szóló műszaki jelentés tervezete
  •   dok. sz. 1886: Gabriel Dos Reis, Bjarne Stroustrup (2005. október 20.)C++ fogalmak meghatározása
  •   dok. sz. 1891: Walter E. Brown (2005. október 18.)Haladás az opaque Typedefs irányába C++0X-hez
  •   dok. sz. 1898: Michel Michaud, Michael Wong (2004. október 6.)Szállítmányozás és örökölt konstruktorok
  •   dok. sz. 1919: Bjarne Stroustrup, Gabriel Dos Reis (2005. december 11.)Inicializáló listák
  •   dok. sz. 1968: V Samko J Willcock, J Järvi, D Gregor, A Lumsdaine (2006. február 26.)Lambda kifejezések és lezárások a C++
  •   dok. sz. 1986: Herb Sutter, Francis Glassborow (2006. április 6.)Konstruktorok delegálása (3. változat)
  •   dok. sz. 2016: Hans Boehm, Nick Maclaren (2002. április 21.)A volatilenek meg kell szereznie az atomitást és a szál láthatósági szemantikáját?
  •   dok. sz. 2142: ISO/IEC DTR 19768 (2007. január 12.)A C++ Evolution állapota (a 2007-es portlandi és oxfordi találkozók között)
  •   dok. sz. 2228: ISO/IEC DTR 19768 (2007. május 3.)A C++ Evolution állapota (Oxford 2007 Meetings)
  •   dok. sz. 2258: G. Dos Reis és B. Stroustrupsablonok álnevei
  •   dok. sz. 2280: Lawrence Crowl (2007. május 2.)Thread-Local Storage
  •   dok. sz. 2291: ISO/IEC DTR 19768 (2007. június 25.)A C++ Evolution állapota (Toronto 2007 Meetings)
  •   dok. sz. 2336: ISO/IEC DTR 19768 (2007. július 29.)A C++ Evolution állapota (Toronto 2007 Meetings)
  •   dok. sz. 2389: ISO/IEC DTR 19768 (2007. augusztus 7.)A C++ Evolution állapota (Kona 2007 előtti találkozók)
  •   dok. sz. 2431: SC22/WG21/N2431 = J16/07-0301 (2007. október 2.),A nullmutató neve: nullptr
  •   dok. sz. 2432: ISO/IEC DTR 19768 (2007. október 23.)A C++ Evolution állapota (a Kona 2007 utáni találkozója)
  •   dok. sz. 2437: Lois Goldthwaite (2007. október 5.)Explicit konverziós operátorok
  •   dok. sz. 2461: ISO/IEC DTR 19768 (2007. október 22.)Munkatervezet, szabvány a C++ programozási nyelvhez
  •   dok. sz. 2507: ISO/IEC DTR 19768 (2008. február 4.)A C++ Evolution állapota (a Bellevue 2008 előtti találkozója)
  •   dok. sz. 2544: Alan Talbot, Lois Goldthwaite, Lawrence Crowl, Jens Maurer (2008. február 29.)Korlátlan szakszervezetek
  •   dok. sz. 2565: ISO/IEC DTR 19768 (2008. március 7.)A C++ Evolution állapota (a Bellevue 2008 utáni találkozója)
  •   dok. sz. 2597: ISO/IEC DTR 19768 (2008. április 29.)A C++ Evolution állapota (az Antipolis 2008 előtti találkozója)
  •   dok. sz. 2606: ISO/IEC DTR 19768 (2008. május 19.)munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 2697: ISO/IEC DTR 19768 (2008. június 15.)A WG21 2008. június 8-15. ülésének jegyzőkönyve
  •   dok. sz. 2798: ISO/IEC DTR 19768 (2008. október 4.)munkatervezet, szabvány a C++ programozási nyelvhez
  •   dok. sz. 2857: ISO/IEC DTR 19768 (2009. március 23.)munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 2869: ISO/IEC DTR 19768 (2009. április 28.)A C++ Evolution állapota (2008-as San Francisco-i találkozó után)
  •   dok. sz. 3000: ISO/ISC DTR 19769 (2009. november 9.)Munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 3014: Stephen D. Clamage (2009. november 4.)NAPIREND, PL22.16. számú ülés. 53, WG21 találkozó sz. 48, 2010. március 8-13., Pittsburgh, PA
  •   dok. sz. 3082: Herb Sutter (2010. március 13.)C++0x Meeting menetrend
  •   dok. sz. 3092: ISO/ISC DTR 19769 (2010. március 26.) Munkavázlat, Szabvány a C++ programozási nyelvhez
  •   dok. sz. 3126: ISO/ISC DTR 19769 (2010. augusztus 21.) munkavázlat, szabvány a C++ programozási nyelvhez
  •   dok. sz. 3225: ISO/ISC DTR 19769 (2010. november 27.)Munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 3242: ISO/ISC DTR 19769 (2011. február 28.)Munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 3291: ISO/ISC DTR 19769 (2011. április 5.)munkatervezet, C++ programozási nyelv szabvány
  •   dok. sz. 3290: ISO/ISC DTR 19769 (2011. április 5.)FDIS, C++ programozási nyelv szabvány
  •   dok. sz. 3337 : Dátum: 2012-01-16 Munkatervezet, Szabvány a C++ programozási nyelvhez

Linkek

Irodalom

  • Stanley B. Lippman, Josy Lajoye, Barbara E. Moo. C++ programozási nyelv. Core Course 5. kiadás = C++ Primer (5. kiadás). - M. : "Williams" , 2014. - 1120 p. - ISBN 978-5-8459-1839-0 .
  • Siddhartha Rao. Tanítsd meg magad C++ nyelven 21 nap alatt, 7. kiadás = Sams Teach Yourself C++ in One Hour a Day, 7. kiadás. - M. : "Williams" , 2013. - 688 p. — ISBN 978-5-8459-1825-3 .
  • István Prata. C++ programozási nyelv (C++11). Előadások és gyakorlatok, 6. kiadás = C++ Primer Plus, 6. kiadás (Developer's Library). - M. : "Williams" , 2012. - 1248 p. - ISBN 978-5-8459-1778-2 .