Transcript C++11 Nowy standard C++
C++11 / C++14 - wybrane elemnty nowego standardu
Roman Starosolski Przedmiot monograficzny: Metody i Narzędzia Wytwarzania Oprogramowania
Standardy
1983: C with classes -> C++
z virtual, bez klas abstrakcyjnych, dziedziczenia wielobazowego, szablonów, wyjątków, STL …
C++98/C++03
Pierwszy formalny standard i jego korekta
C++TR1 (2007)
Rozszerzona biblioteka standardowa, nieobligatoryjny
C++0x/C++11
Temat dzisiejszego wykładu
C++14 (minor release)
Temat dzisiejszego wykładu
Ciekawe linki zamiast literatury
[1] C++11 FAQ by Bjarne Stroustrup http://www2.research.att.com/~bs/C++0xFAQ.html
[2] C++11 wiki page (jest też wersja PL) http://en.wikipedia.org/wiki/C%2B%2B11 [3] C++14 wiki page http://en.wikipedia.org/wiki/C%2B%2B14 [4] Zaskakująco krytyczny wobec C++11 wywiad z Nicolai Josuttisem http://www.informit.com/articles/article.aspx?p=1846582 [5] An Introduction to Variadic Templates in C++0x by Anthony Williams http://www.devx.com/cplus/Article/41533/0/page/1
Cele opracowania nowej wersji języka
Za: C++11 FAQ by Bjarne Stroustrup [1] – Make C++ a better language for systems programming and library building -- that is, to build directly on C++'s contributions to programming, rather than providing specialized facilities for a particular sub-community (e.g. numeric computation or Windows-style application development).
– Make C++ easier to teach and learn -- through increased uniformity, stronger guarantees, and facilities supportive of novices (there will always be more novices than experts).
Przeznaczenie języka
Better C Data abstraction tool Object-oriented programming tool Generic programming tool
NEW !
auto
Stare znaczenie (zm. automatyczna) nie obowiązuje!
Nowe znaczenie – typ ma zostać określony przez kompilator na podstawie wyrażenia inicjalizującego
auto
list < int > l; for( int i=0; i<10; i++) l.push_back(i); int max = *l.begin(); for ( list list < int > l; for( auto i=0; i<10; i++) l.push_back(i); auto max = *l.begin(); for ( auto p = ++l.begin(); p!=l.end(); ++p) if (max<*p) max=*p; cout<<"max: "< Przykład za [1] template auto tmp = vt[i]*vu[i]; // ... } Dozwolony typ auto jako typ zwracany przez funkcję pod warunkiem że typ wywnioskowany z wszystkich return jest taki sam i że da się wyznaczyć - przykład za[3] auto Correct(int i) { if (i == 1) return i; // return type deduced as int else return Correct(i-1)+i; // ok to call it now } auto Wrong(int i) { if (i != 1) return Wrong(i-1)+i; // Too soon to call this. // No prior return statement. else return i; // return type deduced as int } Pobierz typ wyrażenia, wyrażenie nie jest wartościowane (niektóre kompilatory udostępniały wcześniej op. typeof) Przykład za [1] void f(const vector } // ... } auto jako deklarowany typ zwracany do wyznaczenia na podstawie typu argumentów – Ze względu na zakres (scope) samo „auto” nie wystarczy Przykład za [1] template Lokalna, nienazwana funkcja, do użycia jako argument szablonu (np. Algorytmów STL) zamiast zwykłej funkcji lub obiektu funkcyjnego [&](int a, int b) { return v[a].name Przykład za [1] (zmodyfikowany) void f(vector } Argumenty funkcji mogą być typu auto Argumenty w capture list mogą mieć wartości domyślne (przyk. za [3]) – można w ten sposób wymusić przekazanie argumentu przez move semantics (wyjaśnione później) std::unique_ptr Ujednolicona składnia inicjalizacji agregatów i zm. skalarnych int tab[] = {1, 2, 3, 4}, x={3}, y{4}; vector< string > = {„one”, „two”, „three”, „four”}; Szablon: initializer_list for ( zmienna : zakres) instrukcja; Zakres może być: – Kontener STL, lub inny obiekt z metodami .begin() i .end() – Tablica – string – initializer_list for ( zmienna : zakres) instrukcja; Przykłady za [1] void f(vector T&& - referencja do rvalue, może zostać skojarzona jedynie z nienazwaną zmienną tymczasową - główne zastosowanie: do deklaracji konstruktorów przenoszących/operatorów przypisania - gdy wiadomo, że argument konstruktora nie będzie więcej użyty (np. przy przekazywaniu stringów przez wartość), można przenieść jego zawartość zamiast kopiowania -można jawnie określić, żeby argument operatora/konstruktora uznać za rvalue za pomocą szablonu (przykład na kolejnych slajdach): std::move Przykłady za [1] template vector(const vector&); vector( vector&& ); vector& operator=(const vector&); vector& operator=( vector&& ); // copy constructor // move constructor // copy assignment // move assignment }; // note: move constructor and move assignment takes // non-const && // they can, and usually do, write to their argument Przykłady za [1] template Deklarujemy możliwość wyznaczenia podczas kompilacji – Dla zmiennych/obiektów: zmienna da się tak wyznaczyć (w przeciwnym razie błąd), jest const, może być przechowywana w tablicach kompilatora a nie pamięci – Dla funkcji: funkcja jest prosta (… pojedynczy return z wyrażeniem, bez dekl. zmiennych), jeżeli argumenty będą znane podczas kompilacji, to wynik funkcji też – Dla konstruktorów: jak funkcja, jeżeli argumenty będą znane podczas kompilacji, to cały obiekt nim utworzony też Przykłady za [1] enum Flags { good=0, fail=1, bad=2, eof=4 }; constexpr int x1 = bad|eof; // ok void f(Flags f3) { constexpr int x2 = bad|f3; // error: can't evaluate at compile time int x3 = bad|f3; // ok } Przykłady za [1] enum Flags { good=0, fail=1, bad=2, eof=4 }; constexpr int operator|(Flags f1, Flags f2) { return Flags(int(f1)|int(f2)); } void f(Flags x) { switch (x) { case bad: /* ... */ break; case eof: /* ... */ break; case bad|eof: /* ... */ break; default: /* ... */ break; } } Przykłady za [1] struct Point { int x,y; constexpr Point(int xx, int yy) : x(xx), y(yy) { } }; constexpr Point origo(0,0); constexpr int z = origo.x; constexpr Point a[] = {Point(0,0), Point(1,1), Point(2,2) }; constexpr int x = a[1].x; // x becomes 1 = default – Jawna deklaracja : wygeneruj tę metodę (dotyczy konstruktorów, destruktorów, operatorów przypisania) = delete – Jawna deklaracja : nie generuj tej metody – Jawna deklaracja : nie nie wywołuj (w ten sposób) tej metody nawet, jeżeli się da Przykłady za [2] struct SomeType { SomeType() = default; //The default constructor //is explicitly stated. SomeType(OtherType value); }; Przykłady za [2] struct NonCopyable { NonCopyable & operator=(const NonCopyable&) = delete; NonCopyable(const NonCopyable&) = delete; NonCopyable() = default; }; struct NoInt { void f(double i); void f(int) = delete; }; struct OnlyDouble { void f(double d); template Dla metod – Konstruktor kopiujący – Kostruktor przenoszący – Operator przypisania – Operator przeniesienia (przenoszący operator przypisania) – Destruktor Jeżeli jedna z nich będzie zdefiniowana jawnie, lub określona =default, lub =delete to - pozostałe przenoszące nie zostaną wygenerowane automatycznie - pozostałe nie-przenoszące zostaną wygenerowane (własność ta jest deprecated) Konstruktor bezargumentowy będzie generowany automatycznie jeżeli użytkownik nie zdefiniował żadnego konstruktora Przykłady za [1] class X1 { X1& operator=(const X1&) = delete; }; // Disallow copying // This implicitly also disallows moving of X1s. // Copy initialization is allowed, but deprecated. class X2 { X2& operator=(const X2&) = default; }; // This implicitly also disallows moving of X2s. // Copy initialization is allowed, but deprecated. class X3 { X3& operator=(X3&&) = delete; } // Disallow moving // This implicitly also disallows copying of X3s. Przykład za [2] class SomeType { int number; public: SomeType(int new_number) : number(new_number) {} SomeType() : SomeType(42) {} }; Przykład za [1] class Derived : public Base { public: using Base::f; // lift Base's f into Derived's scope -- works in C++98 void f(char); // provide a new f void f(int); // prefer this f to Base::f(int) using Base::Base; // ... }; // lift Base constructors Derived's scope -- C++11 Derived(char); // provide a new constructor Derived(int); // prefer this constructor to Base::Base(int) Przykład za [1] konstukcje równoważne class A { public: int a = 7; }; class A { public: int a; A() : a(7) {} }; jeżeli inicjalizacja następuje na liście inicjalizacyjnej konstruktora oraz przy deklaracji w kasie to lista inicjalizacyjna ma priorytet i jest wykonywana zamiast (a nie po lub przed) inicjalizacją z deklaracji Można zadeklarować, że metoda nadpisuje inną, jeżeli się pomylimy i nie będzie nadpisywała to kompilator zgłosi błąd Przykład za [2] struct Base { virtual void some_func(float); }; struct Derived : Base { virtual void some_func(int) override ; // ill-formed because it doesn't override a base class method }; Za pomocą final deklarujemy – że metody już nie będzie wolno nadpisać – że klasy nie będzie wolno odziedziczyć – (wcześniej używano do tego celu dziedziczenia i sekcji private (niedoskonałe)) Przykład za [2] struct Base1 final { }; struct Derived1 : Base1 { }; //ill-formed because the class Base1 has been marked final struct Base2 { virtual void f() final ; }; struct Derived2 : Base2 { void f(); // ill-formed because the virtual function Base2::f has been marked final }; Literal operator - nowy operator przeciążony Przykład za [1] Bignum operator"" x (const char* p) { return Bignum(p); } void f(Bignum); f(1234567890123456789012345678901234567890 x ); Argument operatora może być przekazany jako albo łańcuch (tzw. raw literals), albo jako wartość jednego z kilku typów (cooked), możliwości: – całkowitoliczbowy: operator pobiera unsigned long long lub (jak w przykładzie powyżej) const char* argument. – zmiennopozycyjny: operator pobiera long double lub const char* – łańcuchowy: 2 argumenty operatora (const char*, size_t), możliwe użycie różnych typów znakowych – Literał znakowy: operator pobiera argument typu char Przykłady za [2] OutputType operator "" _suffix(unsigned long long); OutputType operator "" _suffix(long double); … OutputType some_variable = 1234_suffix; // uses the first function OutputType another_variable = 3.1416_suffix; // uses the second function OutputType operator "" _suffix(const char * string_values, size_t num_chars); OutputType operator "" _suffix(const wchar_t * string_values, size_t num_chars); OutputType operator "" _suffix(const char16_t * string_values, size_t num_chars); OutputType operator "" _suffix(const char32_t * string_values, size_t num_chars); … OutputType some_variable = "1234"_suffix; //Calls the const char * version OutputType some_variable = u8"1234"_suffix; //Calls the const char * version OutputType some_variable = L"1234"_suffix; //Calls the const wchar_t * version OutputType some_variable = u"1234"_suffix; //Calls the const char16_t * version OutputType some_variable = U"1234"_suffix; //Calls the const char32_t * version Dla szablonów, zamiast typedef, wygodniejsza składnia Przykład za [1] template Można tworzyć szablony ze zmienną liczbą argumentów (tzw. variadic templates) – szablony funkcji i klas Prosty przykład za [5], zagadnienie obszerne - szczegóły, inne sposoby dostępu do listy argumentów - patrz [5] template vector< alignas - przykłady za [1] alignas(double) alignas(16) unsigned char c[1024]; char[100]; // array of characters, suitably // aligned for doubles // align on 16 byte boundary enum class Kolor:char (Czerwony, Zielony); - „Strong enum” jawny typ bazowy (musi być całkowity) - wartości tylko w zakresie enumeracji Kolor::Czerwony Nieco inne traktowanie unii (więcej wolno) POD (Plain Old Data) – struktura jak z C, dozwolony konstruktor, 2 warianty long long – min. 64 bity, literały np. 10LL Literały Unicode u8 "I'm a UTF-8 string.” u "UTF-16 string." oraz typy dla szerokich znaków char16_t i char32_t U "UTF-32 string.„ Raw string literals R”( C:\temp\ )” … … … R”xxx( coś)” )xxx” Binary literals – NARESZCIE! 0B0000010 0b0000010 Literały dla std::basic_string ”tekst”s i jednostek czasu z std::chrono::duration Digit separators – dozwolony apostrof dla poprawy czytelności (lub wręcz przeciwnie) małych i dużych liczb (przykład za [2]) auto integer_literal = 1'000'000; auto floating_point_literal = 0.000'015'3; auto binary_literal = 0b0100'1100'0110; auto silly_example = 1'0'0'000'00; [[deprecated]] – atrybut ostrzeżenia o możliwości przyszłego wycofania jego argumentu [[deprecated]] int f(); [[deprecated("g() is thread-unsafe. Use h() instead")]] Szablony dla typów zmiennych (wcześniej: funkcji, klas) Zniesione ograniczenia dla constexpr … … … – Miały służyć do definiowania wymagań (ograniczeń) dla argumentów wzorca (np. „argument nie powinien być wskaźnikiem”) – Nie weszły do standardu, gdyż opóźniłyby i tak spóźnione jego wprowadzenie – Pojawią się w następnym standardzieauto
auto
auto (C++14)
decltype
Alternatywna składnia deklaracji funkcji
Funkcje lambda (a.k.a
. wyrażenia lambda, „lambdy”)
Funkcje lambda (a.k.a
. wyrażenia lambda, lambdy)
Funkcje lambda (C++14)
Ujednolicona inicjalizacja initializer_list
for – nowa składnia
for – nowa składnia
Rvalue reference
Przenoszący konstruktor oraz operator przypisania
Przenoszący konstruktor oraz operator przypisania
constexpr – generalized const expression
constexpr – generalized const expression
constexpr – generalized const expression
= default = delete
= default = delete
Konstruktory i inne metody generowane automatycznie
Konstruktory i inne metody generowane automatycznie
Delegowanie konstruktorów
Dziedziczenie konstruktorów
Inicjalizacja niestatycznych zmiennych składowych klasy
Deklaracja nadpisywania
final
Literały dla własnych typów
Literały dla własnych typów
Template alias
Szablony ze zmienną liczbą argumentów
Inne przegląd
Inne przegląd
Inne – C++14
Inne – duże nowości C++11
Współbieżność, wątki, synchronizacja, dzielona pamięć … Rozszerzenia i ulepszenia biblioteki standardowej (wiele …)
Wielki nieobecny C++11
Koncepty
Dziękuję za uwagę