C++ Rusko: ako sa to stalo

Ak na začiatku hry poviete, že na stene visí kód C++, na konci vás určite zastrelí do nohy.

Bjarne Stroustrup

Od 31. októbra do 1. novembra sa v Petrohrade konala konferencia C++ Russia Piter - jedna z veľkých programátorských konferencií v Rusku, ktorú organizovala JUG Ru Group. Medzi pozvaných rečníkov patria členovia výboru pre štandardy C++, rečníci CppCon, autori kníh O'Reilly a správcovia projektov ako LLVM, libc++ a Boost. Konferencia je zameraná na skúsených C++ vývojárov, ktorí si chcú prehĺbiť svoje odborné znalosti a vymeniť si skúsenosti v živej komunikácii. Študenti, postgraduálni študenti a vysokoškolskí učitelia majú veľmi pekné zľavy.

Moskovskú edíciu konferencie bude možné navštíviť už v apríli budúceho roka, no medzitým vám naši študenti prezradia, čo zaujímavé sa naučili na poslednom podujatí. 

C++ Rusko: ako sa to stalo

Fotografia z konferenčný album

o nás

Na tomto poste pracovali dvaja študenti z National Research University Higher School of Economics - Petrohrad:

  • Liza Vasilenko je študentkou 4. ročníka bakalárskeho štúdia, ktorá študuje programovacie jazyky v rámci programu Aplikovaná matematika a informatika. Po zoznámení sa s jazykom C++ v prvom ročníku na vysokej škole som následne získal skúsenosti s prácou s ním prostredníctvom stáží v tomto odvetví. Moja vášeň pre programovacie jazyky vo všeobecnosti a funkčné programovanie zvlášť sa podpísala na výbere správ na konferencii.
  • Danya Smirnov je študentkou 1. ročníka magisterského programu „Programovanie a analýza údajov“. Ešte na škole som písal úlohy na olympiádu v C++ a potom sa nejako stalo, že jazyk neustále prichádzal do edukačných aktivít a nakoniec sa stal hlavným pracovným jazykom. Rozhodol som sa zúčastniť konferencie, aby som si zlepšil svoje vedomosti a tiež sa dozvedel o nových príležitostiach.

Vedenie fakulty v newsletteri často zdieľa informácie o vzdelávacích akciách súvisiacich s našou špecializáciou. V septembri sme videli informácie o C++ Russia a rozhodli sme sa zaregistrovať ako poslucháči. Toto je naša prvá skúsenosť s účasťou na takýchto konferenciách.

Štruktúra konferencie

  • Správy

V priebehu dvoch dní odborníci prečítali 30 správ, ktoré pokrývajú mnohé horúce témy: dômyselné využitie jazykových funkcií na riešenie aplikovaných problémov, pripravované jazykové aktualizácie v súvislosti s novým štandardom, kompromisy v dizajne C++ a preventívne opatrenia pri práci s ich následkami, príklady zaujímavú architektúru projektu, ako aj niektoré detaily jazykovej infraštruktúry pod kapotou. Súbežne prebiehali tri predstavenia, najčastejšie dve v ruštine a jedno v angličtine.

  • Diskusné zóny

Po prejave boli všetky nepoložené otázky a nedokončené diskusie prenesené do špeciálne určených priestorov na komunikáciu s prednášajúcimi, vybavených tabuľami na označenie. Dobrý spôsob, ako si skrátiť prestávku medzi prejavmi príjemným rozhovorom.

  • Bleskové rozhovory a neformálne diskusie

Ak chcete podať krátku správu, môžete sa prihlásiť na večerný Lightning Talk na tabuli a získať päť minút času na rozhovor o čomkoľvek na tému konferencie. Napríklad rýchly úvod do dezinfekčných prostriedkov pre C++ (pre niektorých to bola novinka) alebo príbeh o chybe pri generovaní sínusoidy, ktorú možno len počuť, ale nie vidieť.

Ďalším formátom je panelová diskusia „Výbor od srdca k srdcu“. Na pódiu sú niektorí členovia normalizačnej komisie, na projektore je krb (oficiálne - na vytvorenie úprimnej atmosféry, ale dôvod „pretože VŠETKO HORIE“ sa zdá vtipnejší), otázky týkajúce sa štandardu a všeobecnej vízie C++ , bez búrlivých technických diskusií a holiwarov. Ukázalo sa, že vo výbore sú aj živí ľudia, ktorí si nemusia byť niečím úplne istí alebo niečo nemusia vedieť.

Pre priaznivcov holivarov zostalo na kauze aj tretie podujatie - BOF session “Go vs. C++”. Vezmeme milovníka Go, milovníka C++, pred začiatkom sedenia spolu pripravia 100500 XNUMX snímok na tému (ako problémy s balíčkami v C++ alebo nedostatok generík v Go) a potom medzi sebou živo diskutujú a s publikom a publikum sa snaží pochopiť dva uhly pohľadu naraz. Ak holivar začne mimo kontextu, moderátor zasiahne a uzmieri strany. Tento formát je návykový: niekoľko hodín po začiatku bola dokončená iba polovica snímok. Záver sa musel značne urýchliť.

  • Partnerské stojany

Partneri konferencie mali zastúpenie v sálach – v stánkoch sa hovorilo o aktuálnych projektoch, ponúkali stáže a zamestnanie, robili kvízy a malé súťaže a žrebovali aj pekné ceny. Zároveň niektoré spoločnosti dokonca ponúkli, že prejdú úvodnými fázami pohovorov, čo by mohlo byť užitočné pre tých, ktorí si prišli nielen vypočuť reportáže.

Technické detaily správ

Oba dni sme počúvali reportáže. Občas bolo ťažké vybrať jednu reportáž z paralelných – dohodli sme sa, že sa rozdelíme a vymeníme si poznatky získané cez prestávky. A aj tak sa zdá, že je toho veľa. Tu by sme chceli hovoriť o obsahu niektorých správ, ktoré nás najviac zaujali

Výnimky v C++ cez prizmu optimalizácií kompilátora, Roman Rusyaev

C++ Rusko: ako sa to stalo
Posunúť z prezentácia

Ako naznačuje názov, Roman sa pozrel na prácu s výnimkami pomocou LLVM ako príkladu. Zároveň pre tých, ktorí nepoužívajú Clang vo svojej práci, môže správa poskytnúť určitú predstavu o tom, ako by sa kód mohol potenciálne optimalizovať. Je to tak preto, lebo vývojári kompilátorov a zodpovedajúcich štandardných knižníc spolu komunikujú a mnohé úspešné riešenia sa môžu zhodovať.

Takže, aby ste zvládli výnimku, musíte urobiť veľa vecí: zavolať manipulačný kód (ak existuje) alebo uvoľniť zdroje na aktuálnej úrovni a roztočiť zásobník vyššie. To všetko vedie k tomu, že kompilátor pridáva ďalšie inštrukcie pre volania, ktoré potenciálne vyvolávajú výnimky. Preto, ak sa výnimka skutočne nevyvolá, program bude stále vykonávať zbytočné akcie. Aby sa nejako znížila réžia, má LLVM niekoľko heuristík na určenie situácií, v ktorých nie je potrebné pridávať kód spracovania výnimiek alebo je možné znížiť počet „extra“ inštrukcií.

Prednášajúci ich skúma asi tucet a ukazuje situácie, v ktorých pomáhajú urýchliť vykonávanie programu, aj tie, kde tieto metódy nie sú použiteľné.

Roman Rusyaev teda vedie študentov k záveru, že kód obsahujúci spracovanie výnimiek nie je možné vždy vykonať s nulovou réžiou a dáva nasledujúce rady:

  • pri rozvoji knižníc sa oplatí zásadne opustiť výnimky;
  • ak sú stále potrebné výnimky, potom vždy, keď je to možné, stojí za to pridať modifikátory noexcept (a const) všade, aby kompilátor mohol optimalizovať čo najviac.

Vo všeobecnosti rečník potvrdil názor, že výnimky je najlepšie využiť na minimum alebo ich úplne opustiť.

Snímky prehľadu sú dostupné na nasledujúcom odkaze: [“Výnimky C++ prostredníctvom optimalizácie kompilátora LLVM”]

Generátory, korutíny a iné sladkosti, ktoré odhaľujú mozog, Adi Shavit

C++ Rusko: ako sa to stalo
Posunúť z prezentácia

Jedna z mnohých správ na tejto konferencii venovaná inováciám v C++20 bola nezabudnuteľná nielen pre farebnú prezentáciu, ale aj pre jasnú identifikáciu existujúcich problémov s logikou spracovania kolekcie (cyklus for, spätné volania).

Adi Shavit zdôrazňuje nasledovné: aktuálne dostupné metódy prechádzajú celou kolekciou a neposkytujú prístup k nejakému internému medzistavu (alebo áno v prípade spätných volaní, ale s veľkým množstvom nepríjemných vedľajších účinkov, ako je Callback Hell) . Zdalo by sa, že existujú iterátory, ale ani s nimi nie je všetko také hladké: neexistujú žiadne spoločné vstupné a výstupné body (začiatok → koniec verzus rbegin → koniec atď.), nie je jasné, ako dlho budeme iterovať? Počnúc C++20 sú tieto problémy vyriešené!

Prvá možnosť: rozsahy. Zabalením iterátorov získame spoločné rozhranie pre začiatok a koniec iterácie a získame aj možnosť skladania. To všetko uľahčuje budovanie plnohodnotných potrubí na spracovanie údajov. Ale nie všetko je také hladké: časť výpočtovej logiky sa nachádza vo vnútri implementácie špecifického iterátora, čo môže komplikovať pochopenie a ladenie kódu.

C++ Rusko: ako sa to stalo
Posunúť z prezentácia

V tomto prípade C++20 pridalo korutíny (funkcie, ktorých správanie je podobné generátorom v Pythone): vykonanie môže byť odložené vrátením nejakej aktuálnej hodnoty pri zachovaní prechodného stavu. Dosiahneme tak nielen prácu s údajmi tak, ako sa javia, ale aj zapuzdrenie všetkej logiky do konkrétnej korutíny.

Ale je tu mucha: v súčasnosti sú iba čiastočne podporované existujúcimi kompilátormi a nie sú implementované tak úhľadne, ako by sme chceli: napríklad sa ešte neoplatí používať odkazy a dočasné objekty v korutínach. Okrem toho existujú určité obmedzenia týkajúce sa toho, čo môžu byť korutíny, a funkcie constexpr, konštruktory/deštruktory a hlavné nie sú zahrnuté v tomto zozname.

Korutíny teda riešia značnú časť problémov s jednoduchosťou logiky spracovania dát, no ich súčasné implementácie si vyžadujú zlepšenie.

materiály:

C++ triky od Yandex.Taxi, Anton Polukhin

Vo svojich profesionálnych aktivitách musím niekedy implementovať čisto pomocné veci: wrapper medzi interným rozhraním a API nejakej knižnice, logovanie alebo parsovanie. V tomto prípade zvyčajne nie je potrebná žiadna dodatočná optimalizácia. Ale čo ak sa tieto komponenty používajú v niektorých z najpopulárnejších služieb na RuNet? V takejto situácii budete musieť spracovať terabajty za hodinu protokolov sami! Potom sa počíta každá milisekunda, a preto sa musíte uchýliť k rôznym trikom – hovoril o nich Anton Polukhin.

Asi najzaujímavejším príkladom bola implementácia vzoru pointer-to-implementation (pimpl). 

#include <third_party/json.hpp> //PROBLEMS! 
struct Value { 
    Value() = default; 
    Value(Value&& other) = default; 
    Value& operator=(Value&& other) = default; 
    ~Value() = default; 

    std::size_t Size() const { return data_.size(); } 

private: 
    third_party::Json data_; 
};

V tomto príklade sa chcem najskôr zbaviť hlavičkových súborov externých knižníc - kompiluje sa to rýchlejšie a môžete sa chrániť pred možnými konfliktmi názvov a inými podobnými chybami. 

Dobre, presunuli sme sa #include do súboru .cpp: potrebujeme predbežnú deklaráciu zabaleného API, ako aj std::unique_ptr. Teraz máme dynamické prideľovanie a ďalšie nepríjemné veci, ako sú údaje rozptýlené v množstve údajov a znížené záruky. std::aligned_storage s tým všetkým môže pomôcť. 

struct Value { 
// ... 
private: 
    using JsonNative = third_party::Json; 
    const JsonNative* Ptr() const noexcept; 
    JsonNative* Ptr() noexcept; 

    constexpr std::size_t kImplSize = 32; 
    constexpr std::size_t kImplAlign = 8; 
    std::aligned_storage_t<kImplSize, kImplAlign> data_; 
};

Jediný problém: musíte zadať veľkosť a zarovnanie pre každý obal - urobme našu šablónu pimpl s parametrami , použite nejaké ľubovoľné hodnoty a pridajte do deštruktora kontrolu, že sme urobili všetko správne: 

~FastPimpl() noexcept { 
    validate<sizeof(T), alignof(T)>(); 
    Ptr()->~T(); 
}

template <std::size_t ActualSize, std::size_t ActualAlignment>
static void validate() noexcept { 
    static_assert(
        Size == ActualSize, 
        "Size and sizeof(T) mismatch"
    ); 
    static_assert(
        Alignment == ActualAlignment, 
        "Alignment and alignof(T) mismatch"
    ); 
}

Keďže T je už definované pri spracovaní deštruktora, tento kód bude správne analyzovaný a vo fáze kompilácie vypíše požadovanú veľkosť a hodnoty zarovnania, ktoré je potrebné zadať ako chyby. Za cenu jedného spustenia kompilácie navyše sa zbavíme dynamickej alokácie zabalených tried, skryjeme API do súboru .cpp s implementáciou a získame aj dizajn, ktorý je vhodnejší na cachovanie procesorom.

Protokolovanie a analýza sa zdali menej pôsobivé, a preto sa v tejto recenzii nebudú spomínať.

Snímky prehľadu sú dostupné na nasledujúcom odkaze: ["C++ triky z Taxi"]

Moderné techniky na udržanie kódu V SUCHU, Björn Fahller

V tejto prednáške Björn Fahller ukazuje niekoľko rôznych spôsobov, ako bojovať proti štylistickým chybám opakovaných kontrol stavu:

assert(a == IDLE || a == CONNECTED || a == DISCONNECTED);

Znie to povedome? Použitím niekoľkých výkonných techník C++ zavedených v najnovších štandardoch môžete elegantne implementovať rovnakú funkčnosť bez akéhokoľvek zníženia výkonu. Porovnaj:   

assert(a == any_of(IDLE, CONNECTED, DISCONNECTED));

Ak chcete zvládnuť nefixný počet kontrol, musíte okamžite použiť variadic šablóny a výrazy skladania. Predpokladajme, že chceme skontrolovať zhodnosť niekoľkých premenných s prvkom enum state_type. Prvá vec, ktorá vám príde na myseľ, je napísať pomocnú funkciu is_any_of:


enum state_type { IDLE, CONNECTED, DISCONNECTED };

template <typename ... Ts>
bool is_any_of(state_type s, const Ts& ... ts) { 
    return ((s == ts) || ...); 
}

Tento medzivýsledok je sklamaním. Zatiaľ kód nie je čitateľnejší:

assert(is_any_of(state, IDLE, DISCONNECTING, DISCONNECTED)); 

Netypové parametre šablóny pomôžu situáciu trochu zlepšiť. S ich pomocou prenesieme spočítateľné prvky enum do zoznamu parametrov šablóny: 

template <state_type ... states>
bool is_any_of(state_type t) { 
    return ((t == states) | ...); 
}
	
assert(is_any_of<IDLE, DISCONNECTING, DISCONNECTED>(state)); 

Použitím auto v netypovom parametri šablóny (C++17) sa prístup jednoducho zovšeobecňuje na porovnania nielen s prvkami state_type, ale aj s primitívnymi typmi, ktoré možno použiť ako netypové parametre šablóny:


template <auto ... alternatives, typename T>
bool is_any_of(const T& t) {
    return ((t == alternatives) | ...);
}

Prostredníctvom týchto postupných vylepšení sa dosiahne požadovaná plynulá syntax pre kontroly:


template <class ... Ts>
struct any_of : private std::tuple<Ts ...> { 
// поленимся и унаследуем конструкторы от tuple 
        using std::tuple<Ts ...>::tuple;
        template <typename T>
        bool operator ==(const T& t) const {
                return std::apply(
                        [&t](const auto& ... ts) {
                                return ((ts == t) || ...);
                        },
                        static_cast<const std::tuple<Ts ...>&>(*this));
        }
};

template <class ... Ts>
any_of(Ts ...) -> any_of<Ts ... >;
 
assert(any_of(IDLE, DISCONNECTING, DISCONNECTED) == state);

V tomto príklade slúži sprievodca dedukciou na navrhnutie požadovaných parametrov šablóny štruktúry kompilátoru, ktorý pozná typy argumentov konštruktora. 

Ďalej - zaujímavejšie. Bjorn učí, ako zovšeobecniť výsledný kód pre porovnávacie operátory nad rámec == a potom pre ľubovoľné operácie. Popri tom sú na príkladoch použitia vysvetlené také vlastnosti ako atribút no_unique_address (C++20) a parametre šablóny vo funkciách lambda (C++20). (Áno, teraz je syntax lambda ešte ľahšie zapamätateľná – ide o štyri po sebe idúce páry zátvoriek všetkého druhu.) Finálne riešenie využívajúce funkcie ako detaily konštruktéra ma naozaj hreje na duši, nehovoriac o výraze tuple v najlepších tradíciách lambda kalkul.

Na záver to nezabudnite vyleštiť:

  • Pamätajte, že lambdy sú constexpr zadarmo; 
  • Pridajme dokonalé preposielanie a pozrime sa na jeho škaredú syntax vo vzťahu k balíku parametrov v uzávere lambda;
  • Dajme kompilátoru viac príležitostí na optimalizáciu s podmieneným noexcept; 
  • Postarajte sa o zrozumiteľnejší chybový výstup v šablónach vďaka explicitným návratovým hodnotám lambd. To prinúti kompilátor vykonať ďalšie kontroly pred skutočným volaním funkcie šablóny - vo fáze kontroly typu. 

Podrobnosti nájdete v materiáloch prednášok: 

Naše dojmy

Naša prvá účasť v C++ Russia bola nezabudnuteľná pre svoju intenzitu. Nadobudol som dojem C++ Russia ako úprimnej udalosti, kde je hranica medzi tréningom a živou komunikáciou takmer nepostrehnuteľná. Všetko, od nálady rečníkov až po súťaže od partnerov podujatia, vedie k búrlivým diskusiám. Obsah konferencie pozostávajúci zo správ pokrýva pomerne širokú škálu tém vrátane inovácií C++, prípadových štúdií veľkých projektov a ideologických architektonických úvah. Bolo by však nefér ignorovať sociálnu zložku podujatia, ktorá pomáha prekonávať jazykové bariéry nielen vo vzťahu k C++.

Ďakujeme organizátorom konferencie za možnosť zúčastniť sa takejto akcie!
Možno ste videli príspevok organizátorov o minulosti, súčasnosti a budúcnosti C++ Russia na blogu JUG Ru.

Ďakujeme za prečítanie a dúfame, že naše prerozprávanie udalostí bolo užitočné!

Zdroj: hab.com

Pridať komentár