Szczegóły ebooka

Wysoce wydajny C++. Opanuj sztukę optymalizowania działania kodu. Wydanie II

Wysoce wydajny C++. Opanuj sztukę optymalizowania działania kodu. Wydanie II

Bjorn Andrist, Viktor Sehr

Ebook

Dzisiejszy C++ jest wyjątkowym językiem programowania. Umożliwia pisanie zwięzłego, stabilnego kodu, który można zoptymalizować pod kątem wydajności w niespotykanym dotychczas stopniu. Język C++ w ciągu ostatnich lat został unowocześniony. W standardzie C++ 20 znalazło się sporo mechanizmów, które pozwalają osiągnąć wysoką efektywność kodu, a równocześnie uprzyjemniają programiście pracę. Poprawiono także ustawienia domyślne kompilatora. To wszystko sprawia, że wielu profesjonalistów wybiera właśnie C++, gdy chce uzyskać kod o wyjątkowej wydajności.

Ta książka jest drugim, zaktualizowanym i uzupełnionym wydaniem przewodnika dla programistów. Rozpoczyna się od szczegółowego wprowadzenia do nowoczesnego C++ z uwzględnieniem technik eliminowania wąskich gardeł w kodzie bazowym. Następnie omówiono zagadnienia optymalizacji struktur danych i zarzadzania pamięcią. Przedstawiono również tematykę algorytmów, zasady pisania czytelnego kodu i stosowania niestandardowych iteratorów. Zamieszczono w niej też praktyczne przykłady używania metaprogramowania w języku C++, korutyn, refleksji (do ograniczenia ilości szablonowego kodu), obiektów pośredniczących (do wprowadzania ukrytych optymalizacji), programowania współbieżnego i struktur danych wolnych od blokad. W końcowej części dokonano przeglądu algorytmów równoległych w C++.

W książce między innymi:

  • nowe aspekty C++ 20
  • wyspecjalizowane struktury danych na potrzeby wydajnego kodu
  • metaprogramowanie i niestandardowe zarządzanie pamięcią
  • mechanizm refleksji i programowanie współbieżne bez używania blokad
  • subtelne optymalizacje algorytmów z biblioteki standardowej C++
  • leniwe generatory i zadania asynchroniczne

Twórz wydajny i czysty kod w C++!

Przedmowa

O autorach

O korektorach merytorycznych

Wprowadzenie

  • Dla kogo przeznaczona jest ta książka?
  • Zawartość książki
  • Jak najlepiej skorzystać z tej książki?
  • Pobieranie plików z przykładowym kodem
  • Stosowane konwencje typograficzne

Rozdział 1. Krótkie wprowadzenie do języka C++

  • Dlaczego C++?
    • Bezkosztowe abstrakcje
    • Przenośność
    • Odporność
    • Język C++ dzisiaj
  • Porównanie C++ z innymi językami
    • Konkurencyjne języki i wydajność
    • Mechanizmy języka C++ niezwiązane z wydajnością
    • Wady języka C++
  • Biblioteki i kompilatory używane w tej książce
  • Podsumowanie

Rozdział 2. Podstawowe techniki języka C++

  • Automatyczne wykrywanie typów za pomocą słowa kluczowego auto
    • Stosowanie słowa kluczowego auto w sygnaturach funkcji
    • Stosowanie słowa kluczowego auto dla zmiennych
  • Semantyka przenoszenia
    • Tworzenie przez kopiowanie, wymienianie i przenoszenie
    • Pozyskiwanie zasobów i reguła pięciu
    • Zmienne nazwane i r-wartości
    • Domyślna semantyka przenoszenia i reguła zera
    • Stosowanie modyfikatora && do funkcji składowych klas
    • Nie przenoś obiektów, jeśli kopiowanie i tak jest pomijane
    • Jeśli to możliwe, stosuj przekazywanie przez wartość
  • Projektowanie interfejsów z obsługą błędów
    • Kontrakty
    • Obsługa błędów
  • Obiekty funkcyjne i wyrażenia lambda
    • Podstawowa składnia lambd w języku C++
    • Klauzula przechwytywania
    • Przypisywanie do lambd wskaźników do funkcji języka C
    • Typy lambd
    • Lambdy i typ std::function
    • Generyczne lambdy
  • Podsumowanie

Rozdział 3. Analizowanie i pomiar wydajności

  • Złożoność asymptotyczna i notacja dużego O
    • Tempo wzrostu
    • Zamortyzowana złożoność czasowa
  • Co mierzyć i w jaki sposób?
    • Aspekty wydajności
    • Przyspieszanie wykonywania kodu
    • Liczniki wydajności
    • Testy wydajności - dobre praktyki
  • Poznaj kod i znajdź hot spoty
    • Profilery z instrumentacją
    • Profilery z próbkowaniem
  • Mikrotesty
    • Prawo Amdahla
    • Pułapki związane z mikrotestami
    • Przykład ilustrujący mikrotesty
  • Podsumowanie

Rozdział 4. Struktury danych

  • Cechy pamięci w komputerach
  • Kontenery z biblioteki standardowej
    • Kontenery sekwencyjne
    • Kontenery asocjacyjne
    • Adaptery kontenerów
  • Używanie widoków
    • Unikanie kopiowania dzięki typowi string_view
    • Unikanie utraty informacji o długości tablic dzięki typowi std::span
  • Uwagi na temat wydajności
    • Zapewnianie równowagi między gwarancjami złożoności a dodatkowymi kosztami
    • Znajomość i stosowanie odpowiednich funkcji API
  • Tablice równoległe
  • Podsumowanie

Rozdział 5. Algorytmy

  • Wprowadzenie do algorytmów z biblioteki standardowej
    • Ewolucja algorytmów z biblioteki standardowej
    • Rozwiązywanie codziennych problemów
  • Iteratory i zakresy
    • Wprowadzenie do iteratorów
    • Wartość wartownika i iteratory zakońcowe
    • Zakresy
    • Kategorie iteratorów
  • Cechy algorytmów standardowych
    • Algorytmy nie zmieniają wielkości kontenera
    • Algorytmy zwracające dane wyjściowe wymagają zaalokowanych danych
    • Algorytmy domyślnie używają funkcji operator==() i operator<()
    • W algorytmach z ograniczeniami używane są projekcje
    • Algorytmy wymagają, aby operatory przenoszące nie zgłaszały wyjątków
    • Algorytmy mają gwarantowaną złożoność
    • Algorytmy działają równie dobrze jak analogiczne funkcje z bibliotek języka C
  • Pisanie i stosowanie algorytmów generycznych
    • Algorytmy niegeneryczne
    • Algorytmy generyczne
    • Struktury danych, które mogą być używane przez algorytmy generyczne
  • Dobre praktyki
    • Stosowanie algorytmów z ograniczeniami
    • Sortowanie tylko tych danych, które będą pobierane
    • Stosowanie algorytmów standardowych zamiast surowych pętli for
    • Unikanie tworzenia kopii kontenera
  • Podsumowanie

Rozdział 6. Zakresy i widoki

  • Powody powstania biblioteki Ranges
    • Ograniczenia biblioteki Algorithm
  • Widoki z biblioteki Ranges
    • Widoki można łączyć w łańcuch
    • Widoki zakresów i adaptery zakresów
    • Widoki są zakresami bez własności elementów oferującymi gwarancje złożoności
    • Widoki nie modyfikują podstawowego kontenera
    • Widoki można materializować do postaci kontenerów
    • Widoki są przetwarzane leniwie
  • Widoki z biblioteki standardowej
    • Widoki dla zakresów
    • Jeszcze o typach std::string_view i std::span
  • Przyszłość biblioteki Ranges
  • Podsumowanie

Rozdział 7. Zarządzanie pamięcią

  • Pamięć w komputerze
    • Wirtualna przestrzeń adresowa
    • Strony pamięci
    • Migotanie
  • Pamięć procesu
    • Pamięć na stosie
    • Pamięć na stercie
  • Obiekty w pamięci
    • Tworzenie i usuwanie obiektów
    • Wyrównanie pamięci
    • Dopełnienie
  • Własność pamięci
    • Pośrednie zarządzanie zasobami
    • Kontenery
    • Inteligentne wskaźniki
  • Optymalizacja małych obiektów
  • Niestandardowe zarządzanie pamięcią
    • Tworzenie puli pamięci
    • Niestandardowy alokator pamięci
    • Stosowanie polimorficznych alokatorów pamięci
    • Implementowanie niestandardowego zasobu pamięciowego
  • Podsumowanie

Rozdział 8. Programowanie z przetwarzaniem w czasie kompilacji

  • Wprowadzenie do metaprogramowania z użyciem szablonów
    • Tworzenie szablonów
    • Stosowanie liczb całkowitych jako parametrów szablonu
    • Tworzenie specjalizacji szablonu
    • Jak kompilator przetwarza funkcję szablonową?
    • Skrócone szablony funkcji
    • Pobieranie typu zmiennej za pomocą specyfikatora decltype
  • Cechy typów
    • Kategorie cech typów
    • Stosowanie cech typów
  • Programowanie z użyciem stałych wyrażeń
    • Działanie funkcji ze słowem kluczowym constexpr w czasie wykonywania programu
    • Deklarowanie funkcji natychmiastowych za pomocą słowa kluczowego consteval
    • Instrukcja if constexpr
    • Sprawdzanie błędów programistycznych w czasie kompilacji
  • Ograniczenia i koncepty
    • Szablon Point2D bez ograniczeń
    • Omówienie składni ograniczeń i konceptów
    • Wersja szablonu Point2D z ograniczeniami
    • Dodawanie ograniczeń do kodu
    • Koncepty w bibliotece standardowej
  • Praktyczne przykłady metaprogramowania
    • Przykład nr 1: tworzenie generycznej bezpiecznej funkcji rzutowania
    • Przykład nr 2: obliczanie skrótów łańcuchów znaków w czasie kompilacji
  • Podsumowanie

Rozdział 9. Podstawowe narzędzia

  • Reprezentowanie wartości opcjonalnych za pomocą typu std::optional
    • Opcjonalne zwracane wartości
    • Opcjonalne zmienne składowe
    • Unikanie pustych stanów w wyliczeniach
    • Sortowanie i porównywanie wartości typu std::optional
  • Kolekcje niejednorodne o stałej wielkości
    • Stosowanie typu std::pair
    • Typ std::tuple
  • Kolekcje niejednorodne o dynamicznie zmienianej wielkości
    • Typ std::variant
    • Kolekcje niejednorodne z obiektami typu std::variant
    • Dostęp do wartości z kontenera elementów typu VariantType
  • Praktyczne przykłady
    • Przykład nr 1: projekcje i operatory porównania
    • Przykład nr 2: refleksja
  • Podsumowanie

Rozdział 10. Obiekty pośredniczące i leniwe przetwarzanie

  • Wprowadzenie do leniwego przetwarzania i obiektów pośredniczących
    • Przetwarzanie leniwe i przetwarzanie zachłanne
    • Obiekty pośredniczące
  • Stosowanie obiektów pośredniczących do zapobiegania tworzeniu obiektów
    • Porównywanie scalanych łańcuchów znaków z wykorzystaniem obiektu pośredniczącego
    • Implementowanie obiektu pośredniczącego
    • Modyfikator r-wartości
    • Przypisywanie połączonej wartości do obiektu pośredniczącego
    • Ocena wydajności
  • Odraczanie obliczania kwadratów
    • Prosta klasa reprezentująca wektory dwuwymiarowe
    • Obliczenia matematyczne
    • Implementowanie klasy LengthProxy
    • Porównywanie długości za pomocą klasy LengthProxy
    • Obliczanie długości za pomocą klasy LengthProxy
    • Ocena wydajności
  • Pomysłowe przeciążanie operatorów i obiekty pośredniczące
    • Operator potoku jako metoda rozszerzająca
  • Podsumowanie

Rozdział 11. Współbieżność

  • Podstawy współbieżności
  • Co sprawia, że programowanie współbieżne jest trudne?
  • Współbieżność a równoległość
    • Porcjowanie czasu
    • Współdzielona pamięć
    • Sytuacja wyścigu
    • Muteks
    • Zakleszczenie
    • Zadania synchroniczne i zadania asynchroniczne
  • Programowanie współbieżne w języku C++
    • Biblioteka obsługi wątków
    • Dodatkowe podstawowe mechanizmy synchronizacji w standardzie C++20
    • Obsługa zmiennych atomowych w języku C++
    • Model dostępu do pamięci w języku C++
  • Programowanie bez blokad
    • Przykład: kolejka bez blokad
  • Wskazówki dotyczące wydajności
    • Zapobieganie rywalizacji
    • Unikanie operacji blokujących
    • Liczba wątków i rdzeni procesora
    • Priorytety wątków
    • Koligacja wątków
    • Niezamierzone współdzielenie
  • Podsumowanie

Rozdział 12. Korutyny i leniwe generatory

  • Kilka przykładów uzasadniających stosowanie korutyn
  • Abstrakcja reprezentująca korutyny
    • Podprocedury i korutyny
    • Wykonywanie podprocedur i korutyn w procesorze
    • Korutyny bezstosowe i korutyny stosowe
    • Czego Czytelnik nauczył się do tego miejsca?
  • Korutyny w języku C++
    • Co zostało uwzględnione w standardzie języka C++ (i co zostało pominięte)?
    • Co sprawia, że funkcja w języku C++ jest korutyną?
    • Minimalny, lecz kompletny przykład
    • Alokowanie stanu korutyny
    • Zapobieganie wiszącym referencjom
    • Obsługa błędów
    • Punkty konfiguracyjne
  • Generatory
    • Implementowanie generatora
    • Stosowanie klasy Generator
    • Praktyczny przykład zastosowania generatorów
  • Wydajność
  • Podsumowanie

Rozdział 13. Programowanie asynchroniczne z użyciem korutyn

  • Jeszcze o typach awaitable
    • Automatyczne punkty wstrzymywania
  • Implementowanie prostego typu reprezentującego zadanie
    • Obsługa zwracanych wartości i wyjątków
    • Wznawianie oczekującej korutyny
    • Dodawanie obsługi zadań zwracających void
    • Synchroniczne oczekiwanie na ukończenie zadania
    • Testowanie asynchronicznych zadań z użyciem funkcji sync_wait()
  • Tworzenie nakładki na API opartym na wywołaniach zwrotnych
  • Współbieżny serwer zbudowany za pomocą biblioteki Boost.Asio
    • Implementowanie serwera
    • Uruchamianie serwera i nawiązywanie z nim połączenia
    • Co osiągnęliśmy za pomocą serwera (i czego wciąż brakuje)?
  • Podsumowanie

Rozdział 14. Algorytmy równoległe

  • Znaczenie równoległości
  • Algorytmy równoległe
    • Ocena algorytmów równoległych
    • Jeszcze o prawie Amdahla
    • Implementowanie równoległego algorytmu std::transform()
    • Implementowanie równoległej wersji algorytmu std::count_if()
    • Implementowanie równoległej wersji algorytmu std::copy_if()
  • Algorytmy równoległe z biblioteki standardowej
    • Strategie wykonywania
    • Obsługa wyjątków
    • Dodatki i zmiany w algorytmach równoległych
    • Zrównoleglanie pętli for opartej na indeksie
  • Wykonywanie algorytmów w procesorze graficznym
  • Podsumowanie
  • Tytuł: Wysoce wydajny C++. Opanuj sztukę optymalizowania działania kodu. Wydanie II
  • Autor: Bjorn Andrist, Viktor Sehr
  • Tytuł oryginału: C++ High Performance: Master the art of optimizing the functioning of your C++ code, 2nd Edition
  • Tłumaczenie: Tomasz Walczak
  • ISBN: 978-83-283-9709-5, 9788328397095
  • Data wydania: 2023-02-14
  • Format: Ebook
  • Identyfikator pozycji: wywyc2
  • Wydawca: Helion