21 Zestawienie Różne żródła

tematy:
Beautiful C++: Updating Legacy Code pluralsight Link
Bjarne Stroustrup: C++11 Style - konferencja





******************

Beautiful C++: Updating Legacy Code
(podobne do C vs C++ z  rozdziału LINK )

-strcpy - z punktu widzenia c++ niebezpieczne (w VC++ uzyj strcpy_s)
-Słowa kluczowe w C++ Link
-deffine nie mają typu i zakresu - uzywaj Const static member
-zamiast Enum użyj enum class (bezpieczne typowanie)
-zamiast makrofunkcji - lambda         [&]() { tresc }  albo Template jeśli potrzebujesz różnych typów

-c++ cechy:
    definiowane własne typy
    RAII * (deterministic destruction )
    Polimorphism (virtualne funkcje i chierarchia dziedziczenia, posługiwanie się ogólnym typem)
    Templates
    Const-correctness -using the keyword const to prevent const objects from getting mutated LINK

*RAII - Przejęcie zasobu jest połączone z konstrukcją, a zwolnienie z automatyczną destrukcją zmiennej. Ponieważ wywołanie destruktora jest automatyczne, gdy zmienna wyjdzie poza swój zasięg, jest zagwarantowane, że zasób zostanie zwolniony od razu gdy skończy się czas życia zmiennej. Stanie się tak również przy wystąpieniu wyjątku. RAII jest kluczową koncepcją przy pisaniu kodu odpornego na błędy. Technika RAII jest używana na przykład przy zakładaniu blokad wątków albo obsłudze plików. Własność pamięci przydzielanej dynamicznie (za pomocą new w C++) może być również kontrolowana za pomocą RAII. Do tego celu biblioteka standardowa C++11 definiuje inteligentne wskaźniki: std::unique_ptr dla obiektów z jednym właścicielem, oraz std::shared_ptr dla obiektów współdzielonych
-czyli twórz w konstruktorze, zwalniaj w destruktorze (destruktor wywoływany automatycznie po przekorczeniu zakresu )
-rozważ sposób tworzenia kopii (płytkie - głębokie) rozważ niekopiowalność (2 konstruktory = delete)  Resource(Resource const& other) = delete;  Resource& operator=(Resource const& other) = delete;

-c++ tworzenie klasy z kodu strukturalnego (funkcje)
    wrzuć zmienne do przestrzeni publicznej, powiązame zmienne stwórz jako nowych memberów (zainicjalizuj w konstruktorze - liście inicjalizacyjnej)
    dodaj publiczne metody na podstawie istniejacych funkcji
    zamien zmienne na prywatne - smprawdz czy działa (enkapsulacja)
    jeśli trzeba dodaj settery i gettery do nich (ale tylko jeśli potrzeba)
    zmienn nazwy zmiennych na klasowe ( m_  )

-jeśli powtarzarz istnienie wielu podobnych funkcji, rozważ dziedziczenie
-uzywaj const gdzie tylko mozesz, dodawaj to na samym początku tworzenia (nie tylko zmienne, ale i funkcje - które nie zmianiają niczego )
-nie używaj Typedef dla structur (styl C)
-uzywaj poprawnego castowania (c++ style   static_cast<>  dynamic_cast<>  reinterpret_cas<>  const_cast<>
-zamien NULL na nullptr
-uzywaj range for
-kiedy konstruktor private? dla niekopiowalnych, nie tworzy obiektu (klasa ze statycznymi elementami) , nie dziedzicznych, Singleton
ale generalnie uzywaj =delete zamiast wrzucać w obszar prywatny
-wymuszenie uzycia konstruktora =default  przeciwnienstwo =delete

STL:
-std::string:  (zamiast tablicy char w stylu C)
   sam zarządza pamięcią
   ma wbudowane funkcje
   przeladowane operatory
   kontener wiec działa z algorytmami
   konwersje
   move semantics

std::vector
   te same zalety co wyżej
   zajmuje ciągły obszar pamięci
   Rozważ std::array for  fixed-size collections

Zamiana starych tablic C na kontenery c++, kroki:
-zacznij tam gdzie tablica char* or [] jest tworzona
-zmien typ zmiennej
-zamien size variable na  .size()
-oczyść kod z delete (kontenery same zwalniają pamięć)
-zastąp pętle wykonujące kod na tablicach, algorytmami
-iteruj Range forem
-zmien funkcje w których przekazywałeś tablice jako argument (rozważ kopie, referencję, const)
-uzyj .c_str()  jeśli potrzebujesz stringa z char*

SmartPointers <memory>
-RAII is great (alocate in constructor - release in destructor, rozważ zachowanie kopi płytka-głęboka)
zastanów się nad lifetime and ownership i wybierz std::unique_ptr  std:share_ptr
sharepointer nie powinien byc pierwszym wyborem, raczej unique  (wymusza argumenty przez &)






Bjarne Stroustrup: C++11 Style - konferencja 

24:15  - przyklad tworzenia jednostek miary
27:22  - keep interfaces strongly typed (avoid general types in interfaces)

Resources and Errors
30:49 RAII - przyklad z otwarciem pliku, uzycie klasy  handle
Resource acquisition is initialization - Przejęcie zasobu jest połączone z konstrukcją, a zwolnienie z automatyczną destrukcją zmiennej
33:34 Resource Handles and Pointers (no naked New!) czysty pointer nie jest
           bezpieczny z rzucaniem wyjatkow, wychodzi z funkcji i nie robi delete.
           uzyj smart ale nie shared_ptr, tylko unique_ptr, wyjdzie z zakresu-skasuje
           po co wogóle pointery a nie lokalne?
           jeśli nie uzywasz danych "na zewnątrz" zrezygnuj całkowicie z pointerów

35:50 Resource Management Style:
-Prefer classes where the resource management is part of their semantics (vextor, thread)
-use "smart pointers" unique for unique ownership, shared for shared
-pamietaj nie uzywaja pointerow jesli nie musisz, pointer to ryzyko race condition!!         

37:54 Move resources - bad example - zastąpione semantyka przenosenia
           (tylko std:array nie moze byc moved, reszta kontenerow moze )

43:21 Style:
-no naked pointers
-keep arrays out of interfaces (prefer containers)
-always consider std::unique_ptr and sometimes std::shared_ptr
-return objects "by value" (its using move not copy - copy elision)
 (no fiddle with pointer,references )

Use compact data:
vector vs List (jeden szybko wstawia, drugi szybko przechodzi do elementu )
ale czemy uzywac kompaktowych (vector)
lista przechowuje dodatkowo wskazniki na poprzedzajacy i nastepny co przy
64 bitowej atchitekturze powoduje ze 100000 elementow w liscie zajmie 6,4MB a vectorze 1,6MB
Pamiętaj dostęp do pamięci jest bardzo wolny, 200 instrukcji na jeden dostęp
im bardziej kompaktowy kontener (mniejszy) tym większa szansa umieszczenia w cache!!!

Prefer algorithm to unstructured code (czesto szybszy, zawsze bezpieczniejszy)
Stay high level:
-for_each alghorithm create the same code than  for loop
-c++ sort() is fastes than C  qsort.

Dziedziczenie:
-uzywaj tylko kiedy masz hierarchiczną strukturę
-nie naduzywaj tego

Watki:
1:05:25 - przyklad watków z async i auto

reguła 0:
korzystaj z deflautowych konstruktorów, jesli napiszesz destruktor dopisz reszte z deflaut.

20 C++17/20


C++ 17
Karta Features of c++17 (link)

Karta Features of c++ 20(link)

Handy C++17 Features (link)

std::optional 

std::variant

if constexpr

C++20 art LINK

C++20 Filmik cppcon2020


.......................................
When you see an article about new C++ features, most of the time you’ll see a description of major elements. Looking at C++17, there are a lot of posts (including articles from this blog) about structured bindings, filesystem, parallel algorithms, if constexpr, std::optional, std::variant… and other prominent C++17 additions.

In this article, I’ll show you 17 smaller C++17 things that will improve your code.

The Language
1. Dynamic Memory Allocation for Over-Aligned Data
2. Inline Variables
3. __has_include Preprocessor Expression
The Standard Library
4. Variable Templates for Traits
5. Logical Operation Metafunctions
6. std::void_t Transformation Trait
7. std::from_chars
8. Splicing for maps and sets
9. try_emplace() Method
10. insert_or_assign() Method
11. Return Type of Emplace Methods
12. Sampling Algorithms
13. gcd(), lcm() and clamp()
14. Shared Pointers and Arrays
15. std::scoped_lock
Removed Elements
16. Removing auto_ptr
17. Removing Old functional Stuff
.........................................



std::optional 

Std::optional dodaje nam możliwość zwrócenia stanu "pusty" - nullopt przy różnych typach.
Stan "pusty" - nullopt, może być sprawdzany warunkiem IF jak w przykładzie:

Przykład działania optional


#include <iostream>
#include <vector>
#include <optional>

void Process(int) { };

int main()
{
    std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 101, 8, 9 };
    std::optional<int> largerThan100;
    
    for (auto& elem : vec)
    {
        Process(elem);
        
        if (elem > 100 && !largerThan100)
            largerThan100 = elem;
    }
    
    // later on selected elements...
    if (largerThan100)
        std::cout << *largerThan100;
}



Można również zwrócić taki stan za pomocą return std::nullopt  jak w poniższym przykładzie:
Drugi przykład działania option

#include <iostream>
#include <vector>
#include <optional>

template <typename TContainer>
std::optional<typename TContainer::value_type> FindVal(const TContainer& container, const typename TContainer::value_type& key)
{
 auto it = std::find(std::begin(container), std::end(container), key);
 if (it != std::end(container))
  return *it;

 return std::nullopt; // or std::nullopt
}

int main()
{
 std::vector<int> v{ 1, 2, 3, 4, 5, 6, 7 };
 auto i = FindVal(v, 1);
 if (i)
  std::cout << *i;
}




std::variant

Std::variant może przyjmować dowolne, wcześniej określone typy, slbo stan pusty (tu realizowany za pomocą std::monostate )

#include <iostream>
#include <vector>
#include <optional>
#include <variant>
#include <cmath>

// aX^2 + bX + c
using TRoots = std::variant<std::monostate, double, std::pair<double, double>>;

TRoots FindRoots(double a, double b, double c)
{
    const auto delta = b*b-4*a*c;

    if (delta > 0.0)
    {
        auto p = sqrt(delta);
        double x1 = (-b + p)/(2*a);
        double x2 = (-b - p)/(2*a);
        return std::pair(x1, x2);
    }
    else if (delta == 0.0)
    {
        return -b/(2*a);
    }
    
    return std::monostate();
}

void ShowRoots(const TRoots& roots)
{
    switch (roots.index())
    {
        case 0: std::cout << "no roots!\n"; break;
        case 1: std::cout << std::get<1>(roots) << '\n'; break;
        case 2: std::cout << std::get<2>(roots).first << ", " << std::get<2>(roots).second << '\n'; break;
    }
}

int main()
{
    ShowRoots(FindRoots(1, -3, 4));
    ShowRoots(FindRoots(-4, 12, -9));
    ShowRoots(FindRoots(2, -11, 5));
}

Patrz na przykład zastosowania std::variant jako nowoczesnej maszyny stanów.
LINK





if constexpr

Pozwala wybierać gałęzie na poziomie kompilowania  na podstawie warunków constexpr (wyrażenie stałe).



template <typename T>
auto get_value(T t) {
  if constexpr (std::is_pointer_v<T>)
    return *t;
  else
    return t;
}

Uproszcza kod Templatów, szczególnie jeśli używane SFINAE
 (Niepowodzenie podstawienia nie jest błędem (SFINAE) odnosi się do sytuacji w C ++, w której nieprawidłowe zastąpienie parametrów szablonu samo w sobie nie jest błędem)


wiecej 303 i 58 (książka Filipek)