6 Niektóre nowe cechy standardu C++11

Podobne dokumenty
IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

PARADYGMATY PROGRAMOWANIA Wykład 4

Szablony funkcji i szablony klas

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) { zdefiniuje. Integer::operator=(ri);

Podstawy programowania skrót z wykładów:

Wykład I. Programowanie II - semestr II Kierunek Informatyka. dr inż. Janusz Słupik. Wydział Matematyki Stosowanej Politechniki Śląskiej

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Programowanie obiektowe, wykład nr 7. Przegląd typów strukturalnych - klasy i obiekty - c.d.

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Automatyczne tworzenie operatora = Integer2& operator=(const Integer& prawy) {

Standard C++0x (C++1x?) Marcin Świderski

Wykład 5: Klasy cz. 3

PROE wykład 3 klasa string, przeciążanie funkcji, operatory. dr inż. Jacek Naruniec

Programowanie obiektowe w C++ Wykład 12

Tablice, funkcje - wprowadzenie

1 Podstawy c++ w pigułce.

Zaawansowane programowanie w C++ (PCP)

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Wykład 8: klasy cz. 4

Lab 9 Podstawy Programowania

Języki C i C++ Wykład: 2. Wstęp Instrukcje sterujące. dr Artur Bartoszewski - Języki C i C++, sem. 1I- WYKŁAD

Podstawy programowania. Wykład: 5. Instrukcje sterujące c.d. Stałe, Typy zmiennych c.d. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Szablony klas, zastosowanie szablonów w programach

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Język C++ Różnice między C a C++

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Podstawy programowania. Wykład 6 Złożone typy danych: struktury, unie. Krzysztof Banaś Podstawy programowania 1

Wprowadzenie do szablonów szablony funkcji

Uwagi dotyczące notacji kodu! Moduły. Struktura modułu. Procedury. Opcje modułu (niektóre)

Wstęp do programowania

Wprowadzenie do szablonów szablony funkcji

Programowanie Komponentowe Zarządzanie obiektami: kontenery

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Obsługa wyjątków. Język C++ WW12

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

W dowolnym momencie można zmienić typ wskaźnika.

Programowanie w języku C++

Zmienne, stałe i operatory

1 Podstawy c++ w pigułce.

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Funkcje przeciążone, konstruktory kopiujące, argumenty domyślne

Programowanie obiektowe. Materiały przygotował: mgr inż. Wojciech Frohmberg

Programowanie obiektowe - Przykładowe zadania egzaminacyjne (2005/2006)

Wprowadzenie w dziedziczenie. Klasa D dziedziczy klasę B: Klasa B klasa bazowa (base class), klasa D klasa pochodna (derived class).

Wykład 4: Klasy i Metody

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Operatory na rzecz typu TString

Programowanie 2. Język C++. Wykład 3.

Programowanie w C++ Wykład 8. Katarzyna Grzelak. 7 maja K.Grzelak (Wykład 8) Programowanie w C++ 1 / 31

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++

2 Przygotował: mgr inż. Maciej Lasota

C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy. C++ - klasy INNE SPOSOBY INICJALIZACJI SKŁADOWYCH OBIEKTU

Paradygmaty programowania

Programowanie obiektowe w C++ Wykład 1

Funkcje. Spotkanie 5. Tworzenie i używanie funkcji. Przekazywanie argumentów do funkcji. Domyślne wartości argumentów

KOTLIN. Język programowania dla Androida

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 5

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Podstawy programowania - 1

Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Wskaźniki w C. Anna Gogolińska

Programowanie Obiektowo Zorientowane w języku c++ Przestrzenie nazw

Wykład 1. Program przedmiotu. Programowanie Obiektowe (język C++) Literatura. Program przedmiotu c.d.:

Wstęp do programowania

Szablony. Szablony funkcji

STL: Lekcja 1&2. Filozofia STL

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Kurs WWW. Paweł Rajba.

Część 4 życie programu

Programowanie Komputerów

Wskaźniki. Informatyka

Języki programowania obiektowego Nieobiektowe elementy języka C++

C++ Przeładowanie operatorów i wzorce w klasach

Wykład 1. Program przedmiotu. Programowanie (język C++) Literatura. Program przedmiotu c.d.:

Wiadomości wstępne Środowisko programistyczne Najważniejsze różnice C/C++ vs Java

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Język C++ zajęcia nr 2

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

PODEJŚCIE OBIEKTOWE. Przykład 1 metody i atrybuty statyczne

Wstęp do Programowania 2

Zaawansowane programowanie w języku C++ Klasy w C++

Microsoft IT Academy kurs programowania

1 P roste e t ypy p d a d n a ych c - c ąg ą g d a d l a szy 2 T y T py p z ł z o ł żo ż ne e d a d n a ych c : T BLICE

Do czego służą klasy?

Programowanie w Internecie. Java

Programowanie obiektowe w języku C++ dr inż. Jarosław Forenc

Podstawy Programowania Obiektowego

Programowanie. Sylwester Arabas. prowadzący ćwiczenia: Magdalena Kuich, Krzysztof Piasecki, Łukasz Dulny. Wydział Fizyki Uniwersytetu Warszawskiego

Składnia C++ Programowanie Obiektowe Mateusz Cicheński

Transkrypt:

6 Niektóre nowe cechy standardu C++11 Na podstawie: Nicolai M. Josuttis: The C++ Standard Library A Tutorial and Reference, Second Edition, Addison-Wesley 6.1 nullptr Dotychczas używano 0 lub NULL do wskazania, że wskaźnik nie ma żadnej wartości. W C++11 pojawiło się słowo kluczowe nullptr. Pozwala to unikać błędów wynikających z mieszania wartości liczbowych ze wskaźnikami, np. void f(int); void f(void*); f(0); // wywołanie f(int) f(null); // wywołanie f(int) jeżeli NULL jest 0, // w przeciwnym przypadku błąd - niejednoznaczne f(nullptr); // wywołanie f(void*) 6.2 auto W C++11 można deklarować zmienną lub obiekt bez określania jego typu, używając słowa kluczowego auto. Na przykład: auto i = 42; // i jest typu int double f(); auto d = f(); // d jest typu double Typ zmiennej jest dedukowany na podstawie inicjacji, stąd inicjacja jest niezbędna: auto i; // błąd nie można zgadnąć typu! Dopuszczalne są dodatkowe kwalifikatory, na przykład: static auto vat = 0.19; Szczególnie przydatne, gdy typ jest określany długim i złożonym wyrażeniem. Na przykład: vector<string> v; auto pos = v.begin(); // pos jest typu vector<string>::iterator auto l = [] (int x) -> bool // l jest typu lambda, // z parametrem int i zwracającym bool ; 6.3 Ujednolicenie inicjacji i listy inicjatorów Wprowadzono inicjację ujednoliconą. Do każdej inicjacji można używać tej samej składni, wykorzystującej nawiasy klamrowe: int values[] 1, 2, 3 ; std::vector<int> v 2, 3, 5, 7, 11, 13, 17 ; std::vector<std::string> cities "Berlin", "New York", "London", "Braunschweig", "Cairo", "Cologne" ; std::complex<double> c4.0,3.0; // równoważne do c(4.0,3.0) 1

Lista inicjacyjna wymusza tzw. inicjację wartością, co oznacza, że nawet zmienne lokalne podstawowych typów, które zwykle mają nieokreśloną wartość inicjalną, są inicjowane zerem lub nullptr (jeżeli są wskaźnikami): int i; // i ma wartość nieokreśloną int j; // j jest zainicjowane przez 0 int* p; // p ma wartość nieokreśloną int* q; // q jest zainicjowane przez nullptr Jednak w notacji z nawiasami klamrowymi nie są możliwe zwężające inicjacje, czyli np. takie, które zmniejszają precyzję lub zmieniają dostarczoną wartość. Na przykład: int x1(5.3); // OK, ale x1 przyjmuje wartość 5 int x2 = 5.3; // OK, ale x2 przyjmuje wartość 5 int x35.0; // Błąd: zwężająca int x4 = 5.3; // Błąd: zwężająca char c17; // OK: chociaż 7 jest typu int, to nie jest zwężająca char c299999; // Błąd: zwężająca(jeśli 99999 nie pasuje jako char) std::vector<int> v1 1, 2, 4, 5 ; // OK std::vector<int> v2 1, 2.3, 4, 5.6 ; // Błąd: zwężająca elementy // typu double do typu int Aby umożliwić stosowanie listy inicjacyjnej do typu zdefiniowanego przez użytkownika, C++11 dostarcza szablonu klasy: std::initializer_list<>. Można jej używać do zapewnienia inicjacji przez listę wartości lub w dowolnym miejscu, w którym chcemy po prostu przetwarzać listę wartości. Na przykład: void print (std::initializer_list<int> vals) for (auto p=vals.begin(); p!=vals.end(); ++p) //przetwarzaj listę wartości std::cout << *p << "\n"; print (12,3,5,7,11,13,17); // przekaż listę wartości do print() Gdy mamy zarówno konstruktory z określoną liczbą parametrów, jak też z listą inicjacyjną, preferuje się te z listą inicjacyjną: class P public: P(int,int); P(std::initializer_list<int>); ; P p(77,5); // wywołuje P::P(int,int) P q77,5; // wywołuje P::P(initializer_list) P r77,5,42; // wywołuje P::P(initializer_list) P s = 77,5; // wywołuje P::P(initializer_list) Bez konstruktora z listą inicjacyjną próba inicjacji r zakończyłaby się błędem. 2

W związku z listami inicjacyjnymi, słowo kluczowe explicit staje się odpowiednie także dla konstruktorów mających więcej niż jeden parametr. Można zatem unieważnić automatyczną konwersję typów dla wielu wartości. Dotyczy to również inicjacji z użyciem =: class P public: P(int a, int b) explicit P(int a, int b, int c) ; P x(77,5); // OK P y77,5; // OK P z 77,5,42; // OK P v = 77,5; // OK (dozwolona domyślna konwersja typów) P w = 77,5,42.; // błąd: w związku ze słowem explicit (niedozwolona // domyślna konwersja typów) void fp(const P&); fp(47,11); // OK, domyślna konwersja z 47,11 na P fp(47,11,3); // Błąd w związku z explicit fp(p47,11); // OK, jawna konwersja 47,11 na P fp(p47,11,3); // OK, jawna konwersja 47,11,3 na P W ten sam sposób konstruktor explicit z listą inicjacyjną unieważnia domyślne konwersje list inicjacyjnych 0, jedną lub więcej wartości inicjalnych. 6.4 Pętle for oparte na zakresie W C++11 dostępny jest nowy rodzaj pętli for, która wykonuje się po wszystkich elementach podanego zakresu, tablicy lub zbioru ( w innych językach taka pętla to foreach). Składnia: for ( decl : coll ) statement Gdzie decl deklaracja każdego elementu z przekazywanego zbioru coll, dla którego jest wykonywana instrukcja statement. Na przykład: for ( int i : 2, 3, 5, 7, 9, 13, 17, 19 ) std::cout << i << std::endl; std::vector<double> vec; for ( auto& elem : vec ) elem *= 3; 3

elem jest referencją co zapobiega wykonywaniu ciała for na lokalnych kopiach elementów wektora. Aby zapobiegać wykonywaniu konstruktorów i destruktorów dla każdego elementu, trzeba zadeklarować bieżący element jako stałą referencję: template <typename T> void printelements (const T& coll) for (const auto& elem : coll) std::cout << elem << std::endl; Dodatkowo, istnieje reguła umożliwiająca wykorzystanie zwykłych tablic w stylu C o stałym rozmiarze. Na przykład: int array[] = 1, 2, 3, 4, 5 ; long sum=0; // wylicz sumę wszystkich elementów for (int x : array) sum += x; for (auto elem : sum, sum*2, sum*4)// wydrukuj pewne wielokrotności sumy std::cout << elem << std::endl; wyprodukuje następujące wyjście: 15 30 60 6.5 Nowe literały łańcuchowe 6.5.1 Surowe literały łańcuchowe Pozwalają zapisywać ciągi znaków jawnie, bez interpretacji. W związku z tym mogą zawierać znaki specjalne, znaki nowej linii itp. Składnia R"delim()delim", gdzie delim, jest ciągiem co najwyżej 16 znaków z podstawowego zestawu kodów ASCII oprócz backslasha, białych znaków i nawiasów. Przykłady: R"(\\n)" to to samo co "\\\\n" R"nc(a\ b\nc()" )nc"; równoważne "a\\\n b\\nc()\"\n " Surowe literały przydają się do definiowania wyrażeń regularnych i w plikach XML. 4

6.5.2 Kodowane literały łańcuchowe Za pomocą prefiksu kodowania można definiować określone kodowanie dla literałów łańcuchowych i w ten sposób uzyskiwać dostęp do większej liczby znaków (internacjonalizacja). Są trzy kodowania Unicode obsługiwane przez C++11: UTF-8, UTF-16 i UTF-32. C++11 dodaje dwa nowe typy znakowe: char16_t i char32_t. Każdy z nich jest zaprojektowany do przechowywania odpowiednio: znaku UTF-16 i znaku UTF-32. Zdefiniowano następujące prefiksy kodowania: u8 kodowanie UTF-8 (typ const char[]), u kodowanie UTF-16 (typ const char16_t[]), U kodowanie UTF-32 (typ const char32_t[]), L (typ const wchar_t[]) napis zakończony znakiem \0. Na przykład: u8"jestem napisem w kodowaniu UTF-8." u"jestem napisem w kodowaniu UTF-16." U"Jestem napisem w kodowaniu UTF-32." L"hello" // definiuje "hello" jako literał łańcuchowy typu wchar_t. Jeden z tych prefiksów może poprzedzać także literę R w łańcuchach surowych. 6.6 Słowo kluczowe noexcept W C++11 dostępne jest słowo kluczowe noexcept, które oznacza, że funkcja nie może rzucać wyjątków lub nie jest na to przygotowana. Na przykład: void foo () noexcept; oznacza, że foo nie będzie rzucała wyjątkami; jeśli spróbuje, program zostanie przerwany. Jest to niebezpieczne może powodować problemy. 6.7 Słowo kluczowe constexpr Umożliwia wyliczanie wyrażeń w czasie kompilacji. Na przykład: constexpr int square (int x) return x * x; float a[square(9)]; // OK od C++11: a ma 81 elementów 6.8 Lambdy C++11 wprowadziło lambdy dopuszczając funkcjonalność inline, która może być teraz używana jako parametr albo obiekt lokalny. Lambdy zmieniają sposób wykorzystywania standardowej biblioteki C++; mogą być używane z algorytmami i kontenerami biblioteki STL a także przy definiowaniu kodu wykonywanego równolegle. 5

6.8.1 Składnia lambd Lambda jest definicją funkcjonalności, która może być wykorzystywana wewnątrz instrukcji i wyrażeń. Można więc wykorzystywać lambdy jako funkcje inline. W najprostszej wersji funkcja lambda nie ma parametru i po prostu coś robi: [] std::cout << "hello lambda" << std::endl; Można ją wywoływać bezpośrednio: [] std::cout << "hello lambda" << std::endl; (); // wyświetla "hello lambda" lub przekazywać do wywołania przez obiekty (w6bp1): auto l = [] std::cout << "hello lambda" << std::endl; ; l(); // wyświetla "hello lambda" Lambda jest zawsze wprowadzana przez klauzulę przechwytywania (ang. lambda introducer): nawiasy kwadratowe, wewnątrz których można określić zmienne przechwytywane (niestatyczne obiekty zewnętrzne) oraz czy odwołanie jest przez referencję. Jeżeli nie jest potrzebny dostęp do żadnych danych zewnętrznych, nawiasy pozostają puste. Można używać obiektów statycznych takich jak std::cout. Między klauzulą przechwytywania a ciałem lambdy można umieszczać parametry, opcję mutable, specyfikację wyjątków i typ wyniku. Wszystkie są opcjonalne, ale jeśli którykolwiek wystąpi, to nawiasy otaczające parametry stają się obowiązkowe. #include <iostream> int main() auto l = [](int i, int j)->int return i + j; ; std::cout<<l(2,3)<<std::endl; return 0; Jak każda inna funkcja, lambda może mieć parametry: auto l = [] (const std::string& s) std::cout << s << std::endl; ; l("hello lambda"); // wyświetla hello lambda 6

Lambdy nie mogą być szablonami funkcji wszystkie typy danych muszą być dokładnie określone. Lambda może też zwracać wartość. Jeżeli typ zwracanej wartości nie zostanie w żaden sposób określony, to jest dedukowany ze zwracanej wartości. Na przykład typem wartości zwracanej w następującej lambdzie jest int. [] return 42; Aby określić typ zwracany, można wykorzystać nową składnię dostępną teraz także dla zwykłych funkcji znaki -> po nawiasie zamykającym listę parametrów. Na przykład poniższa lambda zwraca 42.0: [] () -> double return 42; Pomiędzy parametrami a typem zwracanym lub ciałem lambdy można określić specyfikację wyjątków, jak w zwykłej funkcji. 6.8.2 Przechwytywanie (dostęp do danych zewnętrznych) Wewnątrz klauzuli przechwytywania można określić sposób przechwytywania dostępu do danych zewnętrznych, które nie są przekazywane jako parametry: [=] przekazywanie przez wartość (można pobierać wartość, nie można jej modyfikować), [&] przekazywanie przez referencję (można pobierać i modyfikować wartość). Ten sposób można określać także osobno dla każdego obiektu. Na przykład ciąg instrukcji (w6ap3): int x=0; int y=42; auto qqq = [x, &y] std::cout << "x: " << x << std::endl; std::cout << "y: " << y << std::endl; ++y; // OK ; x = y = 77; qqq(); qqq(); std::cout << "final y: " << y << std::endl; wygeneruje następujące wyjście: x: 0 y: 77 x: 0 y: 78 final y: 79 Inaczej niż dla zwykłych funkcji, parametrów przekazywanych przez wartość nie wolno modyfikować (kompilator zgłasza błąd składniowy). Zamiast [x, &y] można pisać [=, &y] przekazujemy y przez referencję a pozostałe obiekty przez wartość. 7

6.9 Słowo kluczowe decltype Programowanie obiektowe Wykład 6a Słowo kluczowe decltype to operator pozwalający na uzyskanie typu wyrażenia. Jego głównym przeznaczeniem jest programowanie uogólnione, w którym często trudno, jeśli w ogóle jest to możliwe, określić typy zależne od parametrów szablonu. Stosując słowo kluczowe decltype przekazujemy kompilatorowi wskazówkę, żeby sam określił typ wyrażenia. Nieformalnie, typ zwracany przez decltype jest wydedukowany następująco: 1. jeśli wyrażenie e odwołuje się do zmiennej w zakresie lokalnym lub w przestrzeni nazw, statycznej zmiennej klasy lub parametru funkcji, to wynikiem jest zadeklarowany typ zmiennej lub parametru 2. jeśli e jest wywołaniem funkcji lub użyciem przeciążonego operatora, decltype(e) oznacza zadeklarowany typ wyniku tej funkcji 3. w przeciwnym razie, jeśli e to l-wartość (istnieje dłużej niż przez jedno wyrażenie i można pobrać jej adres), decltype(e) to T&, gdzie T jest typem e; jeśli e jest r-wartością (wartości istniejące tylko przez jedno wyrażenie), to wynikiem jest T. Na przykład: const int&& foo(); int i; struct A double x; ; const A* a = new A(); decltype(foo()) x1; // typ to const int&& decltype(i) x2; // typ to int decltype(a->x) x3; // typ to double decltype((a->x)) x4; // typ to const double& Powodem różnic w ostatnich dwóch wywołaniach decltype jest to, że wyrażenie w nawiasie (a->x) nie jest ani id-expression ani dostępem do członków klasy, a stąd nie oznacza nazwanego obiektu. Ponieważ to wyrażenie jest l-wartością, jego wydedukowany typ jest referencją do typu wyrażenia, czyli const double&. 6.10 Nowa składnia deklaracji funkcji Czasem typ zwracanej przez funkcję wartości zależy od wyrażenia i jego argumentów. W C++11 można deklarować typ zwracanej wartości po liście parametrów (tak jak dla lambd). Można zatem: template <typename T1, typename T2> auto add(t1 x, T2 y) -> decltype(x+y); 6.11 Nowe podstawowe typy danych W C++11 wprowadzono następujące nowe podstawowe typy danych: char16_t (UTF-16) i char32_t (UTF-32) long long i unsigned long long (dla systemów 128-bitowych) std::nullptr_t (typ stałej nullptr) 8