C++11![]() C++11 (dříve C++0x[1]) je standard programovacího jazyka C++, který byl schválen organizací ISO 12. srpna 2011 a nahradil C++03. Označení navazuje na tradici pojmenovávání verzí jazyka podle roku publikování specifikace. C++11 přidává několik prvků k jádru jazyka a rozšiřuje standardní C++ knihovnu. V září 2011 byl standard publikován jako ISO/IEC 14882:2011.[2] Novějšími verzemi jsou C++14, C++17, C++20 a C++23, a pracuje se na verzi C++26.[3][4] Cíle návrhuKomise pro návrh C++11 kladla důraz na:
Významná je pozornost věnovaná začátečníkům, protože velká část programátorů jimi navždy zůstane, a protože si mnoho začátečníků nikdy nerozšíří své znalosti nad rámec těch aspektů jazyka, na které se specializují.[1][5] Rozšíření jádra jazyka C++Jednou z funkcí komise C++ je vývoj jádra jazyka. K oblastem jádra jazyka, které byly výrazně vylepšeny, patří podpora multithreadingu, podpora generického programování, uniformní inicializace a zvyšování výkonnosti. Rozšíření jádra pro rychlejší běhReference jako r-hodnota a přesouvací konstruktorUmožňuje použít referenci na objekt jako r-hodnotu. R-hodnota je dočasná konstanta, do které nelze nijak zapisovat. int a;
a = 5 + 10 // (5 + 10) je r-hodnota
(5 + 10) = a; // nelze přiřadit hodnotu r-hodnotě.
int& b = 10; // nelze, nemůže existovat nekonstantní reference na r-hodnotu, konstanta není uložená v paměti, ale dosazena překladačem
const int& b = 10; // lze, za b se vždy dosadí 10
int&& b = 10; // lze, uloží se do paměti jako dočasná proměnná, inicializuje se na hodnotu 10
Přesouvací konstruktor (anglicky move constructor) zajišťuje přesun prostředků (dat) z jedné třídy do druhé bez alokace a dealokace paměti. C++11 zavádí unární operátor && jako referenci na r-hodnotu, pomocí něhož se definuje přesouvací konstruktor: class Array {
int* pole;
size_t s;
public:
// Konstruktor
Array(size_t s) : s(s) {
pole = new int[s];
}
// Kopírovací konstruktor
Array(const Tr1& par) {
pole = new int[s];
memcpy(pole, par.pole, sizeof(int) * s);
}
// Přesouvací konstruktor
Array(Tr1&& par) {
pole = par.pole;
s = par.s;
par.pole = 0;
par.s = 0;
}
~Array() {
delete[] pole;
}
};
Array pole1(100); // Zavolá standardní konstruktor
Array pole2(static_cast<Array&&>(pole1)); // Přetypuje pole1 na referenci na r-hodnotu, a zavolá přesouvací konstruktor
// Po provedení příkazu bude pole2 obsahovat to, co před provedením příkazu obsahovalo pole1; a pole1 bude prázdné
Obecné konstantní výrazyC++11 zavádí klíčové slovo int get_five() {
return 5;
}
int some_value[get_five() + 7]; // Nelze použít, get_five() není konstantní výraz
enum {
five = get_five(); // Nelze použít, get_five() není konstantní vyraz
};
constexpr int get_five() {
return 5;
}
int some_value[get_five() + 7];
enum {
five = get_five();
};
Nová definice PODTřída nebo struktura v C++03 musí splňovat několik podmínek, aby byla považována za plain old data (POD) typ. Typy, které této definici vyhovují, vytvářejí rozvržení objektů, které je kompatibilní s jazykem C, a je možné je inicializovat staticky. Norma C++03 má omezení na to, jaké typy jsou kompatibilní s jazykem C a které lze staticky inicializovat, protože neexistuje žádný technický důvod, aby překladač nemohl program přijmout; pokud by někdo úmyslně vytvořil C++03 POD typ a přidal nevirtuální členskou funkci, tento typ by již nebyl POD typem, nemohl by být staticky inicializován, a nebyl by kompatibilní s jazykem C, i kdyby nedošlo ke změně rozložení paměti. C++11 uvolnilo několik pravidel pro POD a rozdělilo koncept POD na dva samostatné koncepty: triviální a se standardní strukturou. Typ, který je triviální, může být staticky inicializován. To znamená, že jeho obsah lze kopírovat funkcí Třída nebo struktura je triviální, pokud:
Konstruktory jsou triviální, pouze pokud třída nemá žádné virtuální členské funkce a žádné virtuální základní třídy. Operace kopírování a přesunu také vyžadují, aby všechny nestatické datové členy byly triviální. Že typ má standardní strukturu, znamená, že uspořádává a pakuje své členy způsobem, které je kompatibilní s jazykem C. Třída nebo struktura je standardní strukturou, pokud:
Třída, struktura nebo union se považuje za POD, pokud je triviální, má standardní strukturu, a veškeré jeho nestatické datové členy a základní třídy jsou PODy. Díky oddělení těchto konceptů je možné se jednoho vzdát, aniž by byl porušen druhý. Třída se složitými přesunovými a kopírovací konstruktory nemusí být triviální, ale pokud má standardní strukturu, může spolupracovat s jazykem C. Podobně třída s veřejnými a soukromými nestatickými datovými členy nebude mít standardní strukturu, ale může být triviální, a pak ji lze kopírovat pomocí Rozšíření jádra pro rychlejší kompilaciExterní šablonaV C++03 musí překladač instanciovat šablonu vždy, když se v kompilační jednotce objeví plně specifikovaná šablona, např.: template class std::vector<myclass>;
Pokud je šablona instanciována se stejnými typy v mnoha kompilačních jednotkách, může to výrazně prodloužit trvání překladu. V C++03 tomu nelze zabránit, ale C++11 zavádí externí deklarace šablon podobné externím deklaracím dat. Používají deklarátor extern template class std::vector<myclass>;
čímž říká překladači, aby v této kompilační jednotce instanciaci šablony neprováděl. Rozšíření jádra pro lepší použití jazykaSeznamy inicializátorůC++11 rozšiřuje statickou inicializaci pole nebo struktury známou z C. Pomocí // inicializace v C
int pole[] = {10, 10}; // inicializace pole
typedef struct {
int a;
int b;
} Struktura;
Struktura strukt = {10, 10}; // inicializace struktury
// inicializace v C++11
class Trida {
public:
Trida(int par);
};
Trida pole[] = {10, 10}; // inicializace pole tříd
class Trida {
public:
Trida(std::initializer_list<int> list);
};
Trida pole = {1, 2}; // inicializace třídy
Typová inferenceC++11 zavádí dvě nové metody, jak deklarovat proměnné. Klíčové slovo auto i = 15; // i bude int;
decltype(i) j; // j bude také int;
Výhodu přináší u složitých typů, zkracuje zápis. // C++03
for(std::vector<int>::const_iterator it = data.cbegin(); it != data.cend(); ++it);
// C++11
for(auto it = data.cbegin(); it != data.cend(); ++it);
For cyklusRozšiřuje o novou definici cyklu for. Tento cyklus je známý z jiných jazyků jako cyklus foreach. int pole[10];
for(int& i : pole) {
}
Tento cyklus lze také použít pro kontejnery, které poskytují metody begin a end. Lambda funkceC++11 zavádí anonymní funkce (lambda funkce). Lambda funkce může být použita také jako uzávěr (anglicky closure). [externí_proměnné](parametry)->návratový_typ { tělo funkce; }
V hranatých závorkách lze předat proměnné z rozsahu platnosti, ve kterém je funkce definovaná. Lze předat všechny, nebo jen výčet a je možné je předat hodnotou nebo referencí. [] // funkce nemá přístup k externím proměnným
[x, &y] // k proměnné x lze ve funkci přistupovat jako k hodnotě, k y jako k referenci
[&] // všechny proměnné jsou předány referencí
[=] // všechny proměnné jsou předány hodnotou
[&, x] // x je předáno hodnotou, všechny ostatní referencí
Příklad lambda funkce: [](int x, int y) { return x + y; } // Návratový typ je implicitní, funkce nevidí žádné proměnné mimo svůj obor platnosti
int a = 10;
[&](int x, int y)->int { return x + y + a; } // Návratový typ je explicitní, funkce má přístup ke všem proměnným z oboru platnosti,
// ve kterém je definována, proměnné jsou předány referencí
[=](int x, int y)->int { return x + y + a; } // proměnné jsou předány hodnotou
Aliasy na jmenné prostorynamespace ab
{
int zdvojnasob(int x)
{
return x*2;
}
}
namespace x=ab;
x::zdvojnasob(5); //Totéž jako ab::zdvojnasob(5)
Nová syntaxe typových aliasů//C++98
typedef int my_type;
//C++11
typedef int my_type; //Zpětná kompatibilita
using my_type=int; //Nová syntaxe
//Toto pomocí typedef nelze:
template<typename T>using ptr=T*;
Alternativní syntaxe funkcíSyntaxe deklarací funkcí ve standardním jazyce C byla pro tento jazyk naprosto dostatečná. Protože se jazyk C++ vyvinul z jazyka C, udržoval základní syntaxi a rozšířil ji, kde to bylo potřebné. Jak se jazyk C++ zesložiťoval, byl vystaven několika limitům, zvláště týkajících se deklarace šablon funkcí. Například v C++03 není toto možné: template<class Lhs, class Rhs>
Ret adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} // Ret musí mít typ jako lhs+rhs
Typ template<class Lhs, class Rhs>
decltype(lhs+rhs) adding_func(const Lhs &lhs, const Rhs &rhs) {return lhs + rhs;} // V C++11 není dovoleno
Tato konstrukce není v C++ povolena, protože C++11 proto nově umožňuje zadat typ návratové hodnoty funkce až za seznamem parametrů a symbolem template<class Lhs, class Rhs>
auto adding_func(const Lhs &lhs, const Rhs &rhs) -> decltype(lhs+rhs) {return lhs + rhs;}
Tuto syntaxi lze používat i pro jednodušší deklarace a definice funkcí: struct SomeStruct
{
auto func_name(int x, int y) -> int;
};
auto SomeStruct::func_name(int x, int y) -> int
{
return x + y;
}
Klíčové slovo Zlepšení konstrukce objektůV C++03 není dovoleno konstruktorům třídy volat jiné konstruktory v seznamu inicializátorů této třídy. Každý konstruktor musí vytvořit veškeré členy své třídy sám nebo zavolat společnou členskou funkci, jako např.: class SomeType
{
public:
SomeType(int new_number)
{
Construct(new_number);
}
SomeType()
{
Construct(42);
}
private:
void Construct(int new_number)
{
number = new_number;
}
int number;
};
Konstruktory bázových tříd nemohou být přímo zpřístupněny odvozeným třídám; každá odvozená třída musí implementovat vlastní konstruktory, i když by stačil konstruktor základní třídy. Nekonstantní datové členy třídy nemohou být inicializovány v místě své deklarace, ale pouze v konstruktoru. C++11 poskytuje řešení všech těchto problémů: C++11 umožňuje, aby konstruktory volaly jiné konstruktory (což se nazývá delegace). To umožňuje, aby konstruktory využívaly chování jiných konstruktorů s minimem přidaného kódu. Delegace jsou dostupné v jiných jazycích, např. v Javě nebo v Objective-C. V C++11 lze místo výše uvedeného kódu definujícího jeden konstruktor s parametrem a druhý bez parametru napsat: class SomeType
{
int number;
public:
SomeType(int new_number) : number(new_number) {}
SomeType() : SomeType(42) {}
};
Stejného efektu by bylo možné dosáhnout tím, že by Delegace konstruktorů přináší určitý problém: zatímco v C++03 je na konci provádění libovolného konstruktoru objekt úplně vytvořen, v C++11 je objekt vytvořen, až když doběhnou všechny konstruktory. Protože je povoleno provádět více konstruktorů, každý delegující konstruktor bude pracovat na plně zkonstruovaném objektu pouze svého typu. Konstruktory odvozených tříd se budou provádět až po dokončení všech delegací v jejich základních třídách. Pro konstruktory základních tříd umožňuje C++11 třídě určit, že konstruktory základní třída budou zděděny. Překladač C++11 tedy vygeneruje kód, který provede dědění a předání odvozené třídy základní třídě. Jde o přístup typu „všechno nebo nic“: buď budou předány všechny konstruktory dané základní třídy nebo žádný z nich. Také zděděný konstruktor bude zastíněn, pokud se shoduje se signaturou konstruktoru odvozené třídy, a existují omezení pro vícenásobnou dědičnost: konstruktory třídy nelze dědit ze dvou tříd, které používají konstruktory se stejnou signaturou. Syntaxe je následující: class BaseClass
{
public:
BaseClass(int value);
};
class DerivedClass : public BaseClass
{
public:
using BaseClass::BaseClass;
};
C++11 dovoluje tuto syntaxi pro inicializaci členů: class SomeClass
{
public:
SomeClass() {}
explicit SomeClass(int new_value) : value(new_value) {}
private:
int value = 5;
};
Libovolný konstruktor této třídy bude inicializovat Může také místo inicializace přiřazením uvedené výše použít konstruktor nebo uniformní inicializaci. Explicitní předefinování a finalV C++03 může programátor omylem vytvořit novou virtuální funkci, když chtěl předefinovat funkci základní třídy. Například: struct Base
{
virtual void some_func(float);
};
struct Derived : Base
{
virtual void some_func(int);
};
Předpokládáme, že <code Derived::some_func měla nahradit metodu základní třídy. Ale protože má jinou signaturu, vytvoří další virtuální funkci. To je častý problém, ke kterému dochází zvláště tehdy, když uživatel chce modifikovat základní třídu. C++11 umožňuje tento problém řešit takto: struct Base
{
virtual void some_func(float);
};
struct Derived : Base
{
virtual void some_func(int) override; // chyba - nepředefinovává metodu základní třídy
};
Speciální identifikátor C++11 také umožňuje zabránit dědění z třídy nebo jednoduše zabránit předefinování metody v odvozených třídách. K tomuto účelu slouží speciální identifikátor struct Base1 final { };
struct Derived1 : Base1 { }; // chybné, protože třída Base1 byla označena jako final
struct Base2
{
virtual void f() final;
};
struct Derived2 : Base2
{
void f(); // chybné, protože virtuální funkce Base2::f byla označena jako final
};
V tomto příkladě příkaz Ani
Konstanta a typ nulového ukazateleV této části každý výskyt Od počátků jazyka C v roce 1972 měla konstanta void foo(char *);
void foo(int);
Pokud C++11 opravuje tento problém definováním nového klíčového slova Kvůli zpětné kompatibilitě zůstává char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b je nepravdivé.
int i = nullptr; // chyba
foo(nullptr); // volá foo(nullptr_t), ne foo(int);
/*
Všimněte si, že foo(nullptr_t) skutečně volá foo(char *) ve výše uvedeném příkladě použitím implicitní konverze,
pouze pokud žádné jiné funkce nepřetěžují kompatibilní typy ukazatele v rozsahu platnosti.
Pokud existuje více přetížení, rezoluce selže kvůli nejednoznačnosti,
pokud neexistuje explicitní deklarace foo(nullptr_t).
V hlavičkových souborech pro standardní typy pro C++11 musí typ nullptr_t být deklarován jako:
typedef decltype(nullptr) nullptr_t;
ne jako:
typedef int nullptr_t; // předchozí verze C++, ve kterých musí být NULL být definováno jako 0
typedef void *nullptr_t; // ANSI C, které definuje NULL jako ((void*)0)
* /
Silně typované výčtové typyV C++03 nejsou výčtové typy typově bezpečné. Efektivně to jsou celá čísla, i když jsou výčtové typy různé. To umožňuje porovnávat výčtové hodnoty různých výčtových typů. Jedinou bezpečností, kterou C++03 poskytuje, je, že celá čísla nebo hodnoty jednoho výčtového typu se implicitně nekonvertují na jiný výčtový typ. Podkladové celočíselné typy jsou implementačně závislé; proto je kód, které závisí na velikosti výčtových typů, nepřenositelný. Rozsah platnosti výčtových hodnot je obklopující rozsah platnosti. Proto dva různé výčtové typy ve stejném rozsahu platnosti nemohou mít stejná jména hodnot. C++11 umožňuje speciální klasifikaci výčtových typů bez výše uvedených problémů. Používá deklaraci pomocí enum class Enumeration
{
Val1,
Val2,
Val3 = 100,
Val4 // = 101
};
Tento výčtový typ je typově bezpečný. Hodnoty enum class se implicitně nekonvertují na celá čísla. Proto je nelze porovnávat s celými čísly (výraz Podkladový typ těchto výčtových tříd je vždy známý. Implicitní typ je enum class Enum2 : unsigned int {Val1, Val2};
Výčtové hodnoty starých výčtových typů mají rozsah platnosti rovný obklopujícímu rozsahu platnosti. Výčtové hodnoty nových výčtových typů mají rozsah platnosti daný výčtovou třídou. Ve výše uvedeném příkladě Existuje také přechodová syntaxe umožňující výčtovým hodnotám starého stylu poskytovat explicitní používání rozsahů platnosti a definice podkladového typu: enum Enum3 : unsigned long {Val1 = 1, Val2};
V tomto případě jsou výčtová jména definována s rozsahem platnosti výčtu ( V C++11 jsou také možné dopředné deklarace výčtových typů. Dříve výčtové typy nemohly být deklarovány dopředně, protože jejich velikost závisí na definici jejich členů. Pokud je velikost výčtového typu stanovena explicitně nebo implicitně, mohou být deklarovány dopředně: enum Enum1; // Nepovolené ani v C++03 ani v C++11; podkladový typ nelze určit.
enum Enum2 : unsigned int; // Povolené v C++11, podkladový typ je zadán explicitně.
enum class Enum3; // Povolené v C++11, podkladový typ je int.
enum class Enum4 : unsigned int; // Povolené v C++11.
enum Enum2 : unsigned short; // V C++11 nepovolené, protože Enum2 byl dříve deklarován s odlišným podkladovým typem.
Pravá lomená závorkaSyntaktický analyzátor C++03 definuje C++11 vylepšuje specifikaci analyzátoru, takže tam, kde to má význam, bude několik pravých lomených závorek interpretováno jako uzavření seznamu argumentů šablony. Toto chování lze předefinovat pomocí závorek okolo výrazů v parametrech s použitím binárních operátorů template<bool Test> class SomeType;
std::vector<sometype<1>2>> x1; // Interpretováno jako std::vector položek typu SomeType<true>,
// následované "2 >> x1", což není syntakticky správný deklarátor. 1 je pravdivé.
std::vector<sometype<(1>2)>> x1; // Interpretováno jako std::vector pro SomeType<false>,
// následovaný deklarátorem "x1", což je v C++11 syntakticky správně. (1>2) je nepravdivé.
Explicitní operátory konverzeOd C++98 lze používat klíčové slovo V C++11 lze klíčové slovo Čisté řešení problému bezpečného bool je popsáno na anglických Wikibooks. Šablonové aliasyTyp definovaný pomocí template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
typedef SomeType<othertype, Second, 5> TypedefName; // Chyba!
Tuto konstrukci nelze přeložit. V C++11 je však možné použít šablonový alias: template <typename First, typename Second, int Third>
class SomeType;
template <typename Second>
using TypedefName = SomeType<othertype, Second, 5>;
Klíčové slovo typedef void (*FunctionType)(double); // Starý styl
using FunctionType = void (*)(double); // Nově zavedená syntaxe
Neomezené unionyV C++03 existují omezení, jaké typy objektů mohou být členy unionů; union například nemůže obsahovat žádný objekt, který definuje netriviální konstruktor nebo destruktor. C++11 některá z těchto omezení odstraňuje.[2] Pokud má člen unionu netriviální speciální členskou funkci, překladač nebude generovat ekvivalentní členskou funkci pro union, ale taková funkce musí být definována ručně. Jednoduchý příklad použití unionu v C++11: #include <new> // Pro operátor 'new'.
struct Bod
{
Bod() {}
Bod(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U
{
int z;
double w;
Bod b; // Chyba C++03; povoleno v C++11.
U() {} // Kvůli členu Bod je nutné konstruktor explicitně definovat.
U(const Bod& pt) : b(pt) {} // Vytvoří objekt Bod pomocí seznamu inicializátorů.
U& operator=(const Bod& pt) { new(&p) Bod(pt); return *this; } // Přiřadí objekt Bod použitím 'new'.
};
Změny neovlivní existující kód, protože pouze uvolňují původní pravidla. Vylepšení funkčnosti jádra jazykaTyto vlastnosti umožňují dělat věci, které byly dříve nemožné, jejich zápis byl příliš složitý nebo vyžadovaly nepřenositelné knihovny. Variadické šablony Podrobnější informace naleznete v článku Variadická šablona.
V C++11 mohou mít šablony proměnný počet parametrů, což mj. umožňuje definovat typově bezpečné variadické funkce. Nové řetězcové literályMožnosti řetězcových literálů v C++03 byly značně omezené; kromě řetězců dostupných v jazyce C zapisovaných v uvozovkách, které vytvářejí pole typu C++11 podporuje tři kódování Unicode: UTF-8, UTF-16 a UTF-32. Do definice typu Řetězcové literály pro uvedená kódování se píší takto: u8"Toto je UTF-8 řetězec."
u"Toto je UTF-16 řetězec."
U"Toto je UTF-32 řetězec."
Typ prvního řetězec je obvyklý Do řetězcových literálů v Unicode lze v C++11 snadno vkládat kódové body Unicode: u8"Toto je znak Unicode: \u2018."
u"Toto je větší znak Unicode: \u2018."
U"Toto je znak Unicode: \U00002018."
Číslo za
R"(Řetězcová obsahující \ a " )" R"sep(Řetězcová obsahující \ a " )sep" V prvním případě patří do řetězce vše mezi Syrové řetězcové literály lze používat i pro řetězce Unicode nebo širokých znaků: u8R"XXX(Toto je "syrový UTF-8" řetězec.)XXX" uR"*(Toto je "syrový UTF-16" řetězec.)*" UR"(Toto je "syrový UTF-32" řetězec.)" Uživatelem definované literályC++03 poskytuje různé literály. Zápis C++11 naproti tomu umožňuje uživateli definovat nové druhy modifikátorů literálů, které budou vytvářet objekty vycházející z řetězce znaků, které literál mění. Transformace literálů je předefinována ve dvou různých fázích: syrové a vařené. Syrový literál je posloupnost znaků určitého typu, zatímco vařený literál má zvláštní typ. Literál Literály mohou být rozšířeny v syrové i vařené formě, s výjimkou řetězcových literálů, které lze zpracovávat pouze ve vařené formě. Toto výjimka je způsobena faktem, že řetězce mají předpony, které ovlivňují určitý význam a typ příslušných znaků. Všechny uživatelem definované literály se rozlišují příponami; definování předpon literálů není možné. Všechny přípony začínající libovolným znakem kromě podtržítka ( Jak mají být uživatelem definované literály zpracovány, se definuje operátorem literálu, zapisovaným OutputType operator "" _mysuffix(const char * literal_string)
{
// předpokládá, že OutputType má konstruktor, který bere parametr const char *
OutputType ret(literal_string);
return ret;
}
OutputType some_variable = 1234_mysuffix;
// předpokládá, že OutputType má metodu get_value(), která vrací double
assert(some_variable.get_value() == 1234.0)
Přiřazovací příkaz Druhý možný mechanismus pro zpracování celočíselných syrových literálů a syrových literálů s pohyblivou řádovou čárkou používá variadické šablony: template<char...> OutputType operator "" _tuffix();
OutputType some_variable = 1234_tuffix;
OutputType another_variable = 2.17_tuffix;
Toto instanciuje funkce na zpracování literálů, jako Pro numerické literály je typ vařeného literálu buď OutputType operator "" _suffix(unsigned long long);
OutputType operator "" _suffix(long double);
OutputType some_variable = 1234_suffix; // Používá přetížení 'unsigned long long'.
OutputType another_variable = 3.1416_suffix; // Používá přetížení 'long double'.
V souladu s dříve zmíněnými novými předponami řetězců pro řetězcové literály lze použít: OutputType operator "" _ssuffix(const char * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const wchar_t * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const char16_t * string_values, size_t num_chars);
OutputType operator "" _ssuffix(const char32_t * string_values, size_t num_chars);
OutputType some_variable = "1234"_ssuffix; // Používá přetížení 'const char *'.
OutputType some_variable = u8"1234"_ssuffix; // Používá přetížení 'const char *'.
OutputType some_variable = L"1234"_ssuffix; // Používá přetížení 'const wchar_t *'.
OutputType some_variable = u"1234"_ssuffix; // Používá přetížení 'const char16_t *'.
OutputType some_variable = U"1234"_ssuffix; // Používá přetížení 'const char32_t *'.
Neexistuje žádná alternativní forma šablony. Znakové literály jsou definovány podobně. Paměťový model pro multithreadingSouvisející informace naleznete také v článku Memory model (computing).
C++11 standardizuje podporu vláken. Tato podpora má dvě složky: paměťový model, který umožňuje koexistenci několika vláken v programu a knihovna podpora pro interakce mezi vlákna. (Viz sekce Nástroje pro threading.) Paměťový model definuje, když několik vlákna mohou přístup stejný paměťový umístění, a udává, když aktualizuje jedním vlákno se stane viditelný na jiný vlákna. Vláknové lokální úložištěVe vícevláknovém prostředí je běžné, že každé vlákno má některé jedinečné proměnné. To se děje pro lokální proměnné funkce, ale neděje se to pro globální a statické proměnné. Vláknové lokální úložiště s novým trváním (vedle existujících trvání static, dynamic a automatic) je indikováno specifikátorem úložiště Libovolný objekt, který by měl mít statickou dobu trvání (tj. životnost po celou dobu provádění programu), může mít místo toho dobu trvání Explicitně implicitní speciální členské funkceV C++03 překladač pro třídy, které je samy neposkytují, poskytuje implicitní konstruktor, kopírovací konstruktor, kopírovací operátor přiřazení ( Nad vytvářením těchto implicitních funkcí je však velmi malá kontrola. Pro vytvoření třídy, jejíž objekty nebude možné kopírovat, je možné deklarovat privátní kopírovací konstruktor a kopírovací operátor přiřazení a nedefinovat je. Pokus o použití těchto funkcí bude narušením pravidla jedné definice (ODR). Normou sice není vyžadována diagnostická zpráva,[10] porušení těchto pravidel však mohou způsobit chybu při linkování kódu. Překladač nebude generovat implicitní konstruktor, pokud jsou pro třídu nějaké konstruktory definované. To je v mnoha případech užitečné, je však také užitečné umožnit, aby třída měla jak specializované konstruktory tak překladačem generovaný implicitní konstruktor. C++11 proto zavádí možnost specifikovat, že se má pro třídu vytvořit implicitní speciální členská funkce, nebo že se má implicitní speciální členská funkce zrušit.[11] Následující příklad explicitně vyžaduje, aby byl vytvořen implicitní konstruktor: class SomeType
{
SomeType() = default; // Vyžádání vytvoření implicitního konstruktoru
SomeType(OtherType hodnota);
};
Explicitně smazané funkceC++11 zavádí možnost explicitně zakázat (smazat) funkci. Toho lze využít pro zabránění implicitním typovým konverzím.
Specifikátor void noInt(double i);
void noInt(int) = delete;
Bez uvedení druhého řádku by překladač při použití funkce Pomocí šablony je možné dokonce zakázat volání funkce double onlyDouble(double d) {return d;}
template<typename T> double onlyDouble(T) = delete;
Volání Pomocí specifikátoru class Nekopirovatelna
{
Nekopirovatelna();
Nekopirovatelna(const Nekopirovatelna&) = delete;
Nekopirovatelna& operator=(const Nekopirovatelna&) = delete;
};
Typ long long intV C++03 je největším celočíselným typem Statické aserceC++03 poskytuje dvě metody testování asercí: makro Nový nástroj přináší nový způsob testování aserce v době překladu s použitím nového klíčového slova static_assert (konstantní-výraz, chybová-zpráva); Následující příklady ukazují použití static_assert((GREEKPI > 3.14) && (GREEKPI < 3.15), "GREEKPI je nepřesný!");
template<classT>
struct Check
{
static_assert(sizeof(int) <= sizeof(T), "T není dostatečně velký!");
};
template<classIntegrál>
Integral foo(Integral x, Integral y)
{
static_assert(std::is_integral<integral>::value, "parametr foo() musí být celočíselného typu.");
}
Když je konstantní výraz nepravdivý ( Statické aserce jsou užitečné také mimo šablony. Například určitá implementace algoritmu může záviset na tom, že velikost Umožnění aplikace sizeof na členy třídy bez explicitního objektuV C++03 je možné používat operátor struct SomeType { OtherType clen; };
sizeof(SomeType::clen); // Dostupné v C++11, nedostupné v C++03.
Toto musí vracet velikost typu Ovlivňování zarovnání objektu a dotaz na nějC++11 umožňuje zjišťovat zarovnání proměnných pomocí operátoru Operátor Specifikátor alignas(float) unsigned char c[sizeof(float)]
Umožnění implementace garbage collectoruPředchozí normy C++ umožňovaly implementaci vlastního garbage collectoru pomocí AtributyC++11 poskytuje standardizovanou syntaxi pro rozšiřování jazyka. Taková rozšíření se tradičně zadávala pomocí direktivy int [[attr1]] i [[attr2, attr3]];
[[attr4(arg1, arg2)]], if (cond)
{
[[vendor::attr5]] return i;
}
Ve výše uvedeném příkladu se atribut Doporučuje se, aby atributy neměly žádný sémantický význam v jazyce, a aby se neměnil smysl programu, pokud jsou ignorovány. Atributy mohou být užitečné pro poskytnutí informace, která například pomůže překladači vydat lepší diagnostiku nebo optimalizovat generovaný kód. C++11 poskytuje dva standardní atributy: Změny standardní knihovny C++Ve standardní knihovně C++11 bylo zavedeno několik nových vlastností. Mnoho jich mohlo být implementováno i podle starší normy, ale některé spoléhají (ve větší či menší míře) na nové základní vlastnosti C++11. Velká část nové knihovny byla definována v dokumentu C++ Standards Committee's Library Technical Report (nazývaný TR1), který byl publikován v roce 2005. Různé plné a částečné implementace TR1 jsou aktuálně dostupné použitím jmenného prostoru Rozšíření standardní knihovnyNové hlavičkové soubory:
Vylepšení komponent standardní knihovnyC++11 poskytuje několik nových vlastností, které mohou s výhodou využívat již existující komponenty standardní knihovny. Většina kontejnerů standardní knihovny může například využívat podporu přesunových konstruktorů používajících Rvalue reference, jak pro rychlé přesuny těžkých kontejnerů tak pro přesun obsahu těchto kontejnerů na jiné paměťové lokace. Tam, kde to bylo možné, byly komponenty standardní knihovny vylepšeny o nové jazykové vlastnosti definované v C++11, mimo jiné pro:
Od předešlé normy C++ uplynulo hodně času, během něhož bylo vytvořeno množství kódu, který používá standardní knihovnu, při čemž byly odhaleny složky standardní knihovny, které bylo možné vylepšit. Příkladem je komponenta allocator. Do jazyka C++11 byl začleněn nový model alokátorů založený na oblastech platnosti, který doplňuje předchozí model. Nástroje pro threadingC++03 poskytuje paměťový model, který podporuje threading, ale primární podpora pro skutečné použití threadingu přišla až se standardní knihovnou C++11. Knihovna definuje třídu ( Pro synchronizaci vláken byly do knihovny přidány příslušné mutexy ( Pro vysokou výkonnost při nízkoúrovňové práci je někdy potřebná komunikace mezi vlákna bez režie mutexů. K tomu se používají atomické operace nad paměťovými místy. Ty mohou volitelně specifikovat minimální omezení viditelnosti paměti potřebná pro danou operaci. K tomuto účelu lze také použít explicitní paměťové bariéry. Vláknová knihovna C++11 obsahuje také futures a promises pro předávání asynchronních výsledků mezi vlákny a Další vysokoúrovňové nástroje pro práci s vlákny, např. fondy vláken byly odloženy do budoucí technické zprávy o C++. Nejsou součástí C++11, ale očekává se, že jejich výsledná implementace bude postavena zcela nad vlastnostmi vláknové knihovny. Nový prostředek N-ticeUspořádaná n-tice (anglicky tuple) je kolekce předem daných rozměrů složená z heterogenních objektů. N-tice lze považovat za zobecnění členských proměnných struktur. C++11 verze TR1 typu n-tic využívají C++11 vlastností jako variadické šablony. Pro rozumnou implementaci TR1 verze vyžadovaly implementací definovaný maximální počet obsažených typů, a značné použití triků s makry. Oproti tomu, implementace verze C++11 nevyžaduje žádný explicitní implementací definovaný maximální počet typů. I když překladače budou mít interní maximální hloubku rekurze pro instanciaci šablon (což je normální), n-tice podle C++11 nebudou tuto hodnotu ukazovat uživateli. S použitím variadických šablon vypadá deklarace třídy n-tic takto: template <class...Types> class tuple;
Příklad definice a použití typu n-tice: typedef std::tuple <int, double, long &, const char *> test_tuple;
long lengthy = 12;
test_tuple proof (18, 6.5, lengthy, "Ciao!");
lengthy = std::get<0>(proof); // Přiřadí do 'lengthy' hodnotu 18.
std::get<3>(proof) = " Krásný!"; // Změní čtvrtý prvek n-tice.
Je možné vytvořit n-tici typedef std::tuple <int , double, string > tuple_1 t1;
typedef std::tuple <char, short , const char * > tuple_2 t2 ('X', 2, "Hola!");
t1 = t2; // Ok, první dva prvky mohou být zkonvertovány,
// třetí prvek lze vytvořit z 'const char *'.
Stejně jako auto zaznam = std::make_tuple("Hari Ram", "New Delhi", 3.5, 'A');
std::string name ; float gpa ; char grade ;
std::tie(jmeno, std::ignore, gpa, grade) = zaznam ; // std::ignore umožňuje vypustit jméno města
std::cout << jmeno << ' ' << gpa << ' ' << grade << std::endl ;
Pro n-tice jsou dostupné relační operátory (mezi n-ticemi se stejným počtem prvků), a pro zjišťování charakteristik n-tice (pouze během překladu) jsou k dispozici dva výrazy:
Hašovací tabulkyZahrnutí hašovacích tabulek (neuspořádaných asociativních kontejnerů) do standardní knihovny C++ bylo jedním z nejčastěji se opakujících požadavků, který nebyl obsažen v C++03 pouze z časových důvodů. I když jsou v nejhorším případě (při existenci mnoha kolizí) hašovací tabulky méně efektivní než vyvážené stromy, v mnoha reálných aplikacích fungují lépe. Kolize jsou řešené pouze pomocí lineárního řetězení, protože komise nepovažovala za vhodné standardizovat řešení otevřeného adresování, které přináší množství vnitřních problémů (především když je povoleno mazání položek). Aby se zabránilo kolizím jmen s nestandardními knihovnami, které vyvinuly vlastní implementace hašovacích tabulek, byla místo „hash“ použita předpona „unordered“. Nová knihovna má čtyři typy hašovacích tabulek, které se liší podle toho, zda dovolují prvky se stejným klíčem (jedinečné klíče nebo ekvivalentní klíče), a zda mapují každý klíč na přidruženou hodnotu. Odpovídají čtyřem existujícím asociativním kontejnerům založeným na binárních vyhledávacích stromech s předponou
Nové třídy splňují všechny požadavky kladené na kontejnervou třídu, a mají všechny metody potřebné pro přístup k prvkům: Hašovací tabulky nevyžadovaly žádné rozšíření jádra jazyka C++ (i když implementace budou využívat různé vlastnosti jazyka C++11), pouze malé rozšíření hlavičkového souboru std::array a std::forward_listKromě hašovací tabulek byly do standardní knihovny přidány dva další kontejnery. Regulární výrazyNová knihovna definovaná v novém hlavičkovém souboru
Funkce Příklad použití #include <regex>
const char *vzorek = R"([^ ,.\t\n]+)"; // najde slova oddělená mezerou, čárkou, tečkou, tabelátorem, znakem konce řádku
std::regex rgx(vzorek); // pro neplatný vzorek vyhodí výjimku
const char *target = "Unseen University - Ankh-Morpork";
// Použij regex_iterator pro identifikaci všech slov s 'target' odděleným znaky 'vzorku'.
auto iter =
std::cregex_iterator(target, target + strlen(target), rgx);
// ukončí iterátor posloupnosti
auto end =
std::cregex_iterator();
for (; iter != end; ++iter)
{
std::string match_str = iter->str();
std::cout << match_str << '\n';
}
Knihovna Univerzální smart pointery Podrobnější informace naleznete v článku Smart_pointer#C++ smart pointers.
C++11 poskytuje Rozšiřitelné nástroje pro generování náhodných číselStandardní knihovna jazyka C umožňuje generovat pseudonáhodná čísla pomocí funkce Vytváření náhodných čísel v C++11 je rozděleno na dvě části: generátor, který obsahuje generátor stavu náhodných čísel a produkuje pseudonáhodná čísla; a rozdělení, které určuje rozsah a matematické rozdělení výsledku. Tyto dvě části jsou zkombinovány pro vytvoření objektu generátoru náhodných čísel. Kromě standardní funkce
C++11 také poskytuje několik nejpoužívanějších rozdělení:
Generátor a distribuci lze kombinovat jako v tomto příkladě: #include <random>
#include <functional>
std::uniform_int_distribution<int> rozdeleni(0, 99);
std::mt19937 stroj; // Mersenneho twister MT19937
auto generator = std::bind(rozdeleni, stroj);
int random = generator(); // Generuje rovnoměrně rozdělená celá čísla mezi 0 a 99.
int random2 = distribution(stroj); // Generují jiný vzorek přímo pomocí objektů rozdělení a stroj.
AdaptérAdaptér (anglicky wrapper) se získá z instance šablony třídy Adaptéry jsou užitečné především pro funkční šablony, kde jsou potřeba reference na parametry, nikoli kopie: // Tato funkce dostane odkaz na parametr 'r' a inkrementuje jej.
void func (int &r) { r++; }
// Funkční šablona.
template<class F, class P> void g (F f, P t) { f(t); }
int main()
{
int i = 0;
g (func, i); // 'g<void(int &r), int>' je instanciováno
// pak 'i' nebude změněno.
std::cout << i << std::endl; // Vypíše -> 0
g (func, std::ref(i)); // 'g<void(int &r),reference_wrapper<int>>' je instanciováno
// pak 'i' bude změněno.
std::cout << i << std::endl; // Vypíše -> 1
}
Tento nový nástroj byl přidán k existujícímu hlavičkovému souboru Polymorfní adaptéry pro objekty funkcíPolymorfní adaptéry pro objekty funkcí se sémanticky a syntakticky podobají ukazatelům na funkce, ale jsou méně striktně vázaný a mohou se bez rozdílů odkazovat na cokoli, co lze volat (ukazatele na funkce, ukazatele na členské funkce nebo funktory), jejichž argumenty jsou kompatibilní s argumenty adaptéru. Příklad může vyjasnit jeho charakteristiky: std::function<int(int, int)> func; // Vytvoření adaptéru použitím
// šablonové třídy 'function'.
std::plus<int> add; // 'plus' je deklarováno jako 'šablona<classT> T plus( T, T ) ;'
// pak 'add' je typu 'int add( int x, int y )'.
func = add; // OK - Parametry a návratové typy jsou stejné.
int = func (1, 2); // POZNÁMKA: pokud se adaptér 'func' neodkazuje na žádnou funkce,
// bude vyhozena výjimka 'std::bad_function_call'.
std::function<bool(short, short)> func2 ;
if (!func2)
{
// Pravdivé, protože do 'func2' ještě nebyla přiřazena funkce.
bool adjacent(long x, long y);
func2 = &adjacent; // OK - Parametry a návratové typy jsou konvertovatelné.
struct Test
{
bool operator()(short x, short y);
};
Test vozidlo;
func = std::ref(vozidlo); // 'std::ref' je šablona funkce, které vrací adaptér
// členské funkce 'operator()' struktury 'vozidlo'.
}
func = func2; // OK - Parametry a návratové typy jsou konvertovatelné.
Šablonová třída Typ rysy pro metaprogramováníMetaprogramování je vytváření programů, které vytvářejí nebo mění jiný program (nebo sebe sama). K tomu může docházet při překladu nebo při provádění. Standardizační komise C++ se rozhodla zavést knihovnu pro metaprogramování během překladu se šablonami. Následující metaprogram používá rekurzi instancí šablon pro výpočet celočíselných mocnin podle normy C++03: template<intB, int N>
struct Pow
{
// rekurzivní volání a rekombinace.
enum{ hodnota = B*Pow<b, N-1>::value };
};
template< int B >
struct Pow<b, 0>
{
// ''N == 0'' podmínka pro ukončení.
enum{ hodnota = 1 };
};
int tri_na_ctvrtou = Pow<3, 4>::value;
Mnoho algoritmů může pracovat s různými typy dat; šablony v C++ podporují generické programování a činí kód kompaktnější a užitečnější. Často však algoritmy potřebují informace o typech dat, které používají. Tyto informace lze získat při instanciaci šablony třídy pomocí typových rysů. Typové rysy mohou identifikovat kategorii objektu a všechny charakteristiky třídy (nebo struktury). Jsou definovány v novém hlavičkovém souboru V dalším příkladě existuje šablonová funkce ‘elaborate’, který v závislosti na daný datové typy, bude instanciovat jeden ze dvou navržený algoritmy ( // Poprvé způsob of fungující.
template< bool B > struct Algoritmus
{
template<classT1, class T2> static int do_it (T1 &, T2 &) { /*...*/ }
};
// Druhý způsob of fungující.
template<> struct Algoritmus<true>
{
template<classT1, class T2> static int do_it (T1, T2) { /*...*/ }
};
// Instanciace 'elaborate' bude automaticky instanciovat správný způsob jak pracovat.
template<classT1, class T2>
int elaborate (T1 A, T2 B)
{
// Druhý způsob použít, pouze pokud 'T1' je celé číslo a 'T2' číslo
// s pohyblivou řádovou čárkou, jinak použít první způsob.
return Algorithm<std::is_integral<t1>::value && std::is_floating_point<t2>::value>::do_it( A, B ) ;
}
Pomocí typových rysů definovaných v hlavičkovém souboru Tento typ programování vytváří elegantní a stručný kód; slabinou těchto techniky však je ladění: je nepříjemné při překladu a velmi obtížné při provádění programu. Uniformní metoda výpočtu návratového typu funkčních objektůUrčování návratového typu objektu šablony funkce v době překladu není intuitivní. Zejména pokud návratová hodnota závisí na parametrech funkce. Jako příklad: struct Clear
{
int operator()(int) const; // Typ parametru je
double operator()(double) const; // stejný jako návratový typ.
};
template <classObj>
class Calculus
{
public:
template<class Arg> Arg operator()(Arg& a) const
{
return member(a);
}
private:
Obj member;
};
Instanciací šablony třídy struct Confused
{
double operator()(int) const; // Typ parametru není
int operator()(double) const; // roven návratovému typu.
};
Snaha instanciovat TR1 představilo a C++11 přejalo, šablonovou třídu template< class Obj >
class CalculusVer2
{
public:
template<class Arg>
typename std::result_of<obj(Arg)>::type operator()(Arg& a) const
{
return member(a);
}
private:
Obj member;
};
Díky tomu v instancích funkčního objektu Jedinou změnou oproti verzi Vylepšení kompatibility s jazykem CPro kompatibilitu s jazykem C podle normy C99 byly přidány tyto vlastnosti:[17]
Vlastnosti původně plánované, ale odstraněné nebo nezahrnutéHlavičky pro zvláštní TR:
Odloženo:
Odstraněné a nedoporučované vlastnostiTermín sekvenční bod byl odstraněn. Je nahrazen stanovením, že jedna operace je sekvencována před jinou nebo že dvě operace nejsou sekvencované.[19] Původní použití klíčového slova Dynamická specifikace výjimek je nedoporučovaná.[20] Specifikace funkcí, které nevyhazují výjimky, je v době překladu dostupná pomocí klíčového slova
Základní třídy funkčních objektů ( OdkazyReferenceV tomto článku byl použit překlad textu z článku C++11 na anglické Wikipedii.
Související článkyExterní odkazy
|