C++ Errusia: nola gertatu zen

Antzezlanaren hasieran C++ kodea horman zintzilik dagoela esaten baduzu, amaieran oinetan tiro egingo dizu.

Bjarne Stroustrup

Urriaren 31tik azaroaren 1era, C++ Russia Piter konferentzia egin zen San Petersburgon - Errusiako eskala handiko programazio-jardunaldietako bat, JUG Ru Group-ek antolatuta. Hizlari gonbidatuen artean, C++ Arau Batzordeko kideak, CppCon hizlariak, O'Reilly liburuen egileak eta LLVM, libc++ eta Boost bezalako proiektuen mantentzaileak daude. Jardunaldia zuzeneko komunikazioan esperientzia sakondu eta esperientziak trukatu nahi dituzten C++ garatzaileei zuzenduta dago. Ikasle, graduondoko ikasle eta unibertsitateko irakasleek deskontu oso politak dituzte.

Jardunaldiaren Moskuko edizioa datorren urteko apirilean bisitatu ahal izango da, baina bitartean gure ikasleek azken ekitaldian zer gauza interesgarriak ikasi zituzten kontatuko dizute. 

C++ Errusia: nola gertatu zen

Argazkia hitzaldi-albuma

guri buruz

San Petersburgoko Ekonomiako Ikerketa Nazionaleko Unibertsitateko Goi Eskolako bi ikasle aritu ziren lan honetan:

  • Liza Vasilenko Matematika Aplikatua eta Informatika programaren barruan Programazio Lengoaiak ikasten ari den graduko 4. mailako ikaslea da. Unibertsitateko lehen urtean C++ lengoaia ezagutu ondoren, industrian praktikak eginez esperientzia lortu nuen harekin lan egiten. Programazio-lengoaiekiko zaletasunak, oro har, eta programazio funtzionalarekiko, bereziki, bere aztarna utzi zuen hitzaldiko txostenen aukeraketan.
  • Danya Smirnov "Programazioa eta Datuen Analisia" masterreko 1. mailako ikaslea da. Oraindik eskolan nengoela, Olinpiadetako arazoak C++-n idatzi nituen, eta orduan gertatu zen, nolabait, hizkuntza etengabe agertu zela hezkuntza-jardueretan eta azkenean lan-hizkuntza nagusi bihurtu zela. Jardunaldian parte hartzea erabaki nuen nire ezagutzak hobetzeko eta aukera berriak ezagutzeko ere.

Buletinean, fakultateko zuzendaritzak askotan partekatzen du gure espezialitatearekin lotutako hezkuntza-ekitaldiei buruzko informazioa. Irailean C++ Errusiari buruzko informazioa ikusi genuen eta entzule gisa erregistratzea erabaki genuen. Horrelako jardunaldietan parte hartzeko gure lehen esperientzia da.

Jardunaldien egitura

  • Txostenak

Bi egunetan zehar, adituek 30 txosten irakurri zituzten, gai asko lantzen dituztenak: hizkuntza-eginbideen erabilera asmagarriak aplikatutako arazoak konpontzeko, datozen hizkuntza-eguneratzeak estandar berriarekin lotuta, C++ diseinuan konpromisoak eta haien ondorioekin lan egiteko neurriak, adibideak. proiektuaren arkitektura interesgarria, baita hizkuntza-azpiegituraren azpiko xehetasun batzuk ere. Aldi berean 3 emanaldi izaten ziren, gehienetan bi errusieraz eta bat ingelesez.

  • Eztabaida guneak

Hitzaldiaren ostean, egin gabeko galdera guztiak eta amaitu gabeko eztabaida guztiak espresuki izendatutako guneetara eraman zituzten hizlariekin komunikatzeko, markatzaile-taulez hornituta. Hitzaldien arteko atsedenaldia elkarrizketa atsegin batekin urruntzeko modu ona.

  • Tximista Hitzaldiak eta eztabaida informalak

Txosten labur bat eman nahi baduzu, arratsaldeko Lightning Talk-ean izena eman dezakezu arbelean eta bost minutuko denbora eskura dezakezu hitzaldiaren gaiari buruz hitz egiteko. Adibidez, C++-rako desinfektatzaileei buruzko sarrera azkar bat (batzuentzat berria zen) edo soilik entzun daitekeen, baina ikusten ez den uhin sinusoidalaren sorrerako akats bati buruzko istorio bat.

Beste formatu bat "Bihotz-bihotz batzordearekin" mahai-ingurua da. Eszenatokian normalizazio batzordeko kide batzuk daude, proiektorean tximinia bat dago (ofizialki giro zintzoa sortzeko, baina arrazoia "DENA SUTAN DAGOelako" dibertigarriagoa dirudi), C++-ren estandar eta ikuspegi orokorrari buruzko galderak. , eztabaida tekniko eta holiwars sutsurik gabe. Agertu zen batzordean, agian, zerbaiten guztiz ziur ez dauden edo zerbait jakin ez duten bizidunak ere badaudela.

Holivars-en zaleentzat, hirugarren gertaera kasuan geratu zen - BOF saioa "Go vs. C++". Go maitale bat hartzen dugu, C++ maitalea, saioa hasi aurretik elkarrekin gai bati buruzko 100500 diapositiba prestatzen dituzte (adibidez, C++-n paketeen arazoak edo Go-n generikoen falta), eta gero eztabaida bizia izaten dute euren artean eta ikusleekin, eta ikusleak aldi berean bi ikuspuntu ulertzen saiatzen dira. Holivar bat testuingurutik kanpo hasten bada, moderatzaileak esku hartzen du eta alderdiak adiskidetzen ditu. Formatu honek mendekotasuna sortzen du: hasi eta ordu batzuetara, diapositiben erdiak baino ez ziren osatu. Amaiera asko azkartu behar izan zen.

  • Bazkideen standak

Jardunaldiko bazkideak aretoetan ordezkatuta egon ziren - standetan egungo proiektuei buruz hitz egin zuten, praktikak eta enplegua eskaini zuten, galdetegiak eta lehiaketa txikiak egin zituzten eta sari politak ere zozketatu zituzten. Aldi berean, enpresa batzuek elkarrizketen hasierako faseetatik pasatzea ere eskaini zuten, eta hori erreportajeak entzutera ez ezik etortzen zirenentzat erabilgarria izan zitekeen.

Txostenen xehetasun teknikoak

Bi egunetan erreportajeak entzun genituen. Batzuetan zaila zen erreportaje bat paraleloen artean aukeratzea – atsedenaldietan lortutako ezagutzak banatu eta trukatzea adostu genuen. Eta hala ere, badirudi asko geratzen dela kanpoan. Hemen interesgarrienak iruditu zaizkigun txosten batzuen edukiei buruz hitz egin nahi dugu

C++-n salbuespenak konpiladoreen optimizazioen prismaren bidez, Roman Rusyaev

C++ Errusia: nola gertatu zen
Irristatu ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΈ

Izenburuak dioen bezala, Romanek salbuespenekin lan egitea aztertu zuen LLVM adibide gisa erabiliz. Aldi berean, beren lanean Clang erabiltzen ez dutenentzat, txostenak kodea nola optimizatu daitekeen ideiaren bat eman dezake. Hori horrela da, konpilatzaileen eta dagozkien liburutegi estandarren garatzaileak elkarren artean komunikatzen direlako eta irtenbide arrakastatsu asko bat egin dezaketelako.

Beraz, salbuespen bat kudeatzeko, gauza asko egin behar dituzu: deitu manipulazio-kodeari (baldin badago) edo doako baliabideei uneko mailan eta gora igo pila. Horrek guztiak konpilatzaileak salbuespenak sor ditzaketen deietarako jarraibide gehigarriak gehitzen ditu. Beraz, salbuespena benetan planteatzen ez bada, programak beharrezkoak ez diren ekintzak egingo ditu oraindik. Gastuak nolabait murrizteko, LLVM-k hainbat heuristika ditu salbuespenak kudeatzeko kodea gehitu behar ez den edo "gehigarrizko" jarraibideen kopurua murriztu daitekeen egoerak zehazteko.

Hizlariak dozena bat inguru aztertzen ditu eta programaren exekuzioa bizkortzen laguntzen duten egoerak eta metodo horiek aplikagarriak ez diren egoerak erakusten ditu.

Beraz, Roman Rusyaev-ek ikasleak ondoriora eramaten ditu salbuespenak kudeatzen dituen kodea ezin dela beti exekutatu gainkostu zerorekin, eta aholku hauek ematen ditu:

  • liburutegiak garatzerakoan, merezi du printzipioz salbuespenak alde batera uztea;
  • salbuespenak oraindik behar badira, ahal den guztietan merezi du noexcept (eta const) aldatzaileak gehitzea nonahi, konpilatzaileak ahalik eta gehien optimiza dezan.

Oro har, hizlariak berretsi zuen salbuespenak ahalik eta gehien erabiltzen direla edo guztiz baztertzea dela iritzia.

Txostenaren diapositibak hurrengo estekan daude eskuragarri: ["C++ salbuespenak LLVM konpiladoreen optimizazioen ikuspegitik"]

Sorgailuak, koroutinak eta beste garun-goxotasun batzuk, Adi Shavit

C++ Errusia: nola gertatu zen
Irristatu ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΈ

C++20-ko berrikuntzei eskainitako biltzar honetako txosten ugarietako bat gogoangarria izan zen aurkezpen koloretsuagatik ez ezik, bilduma prozesatzeko logikarekin dauden arazoen identifikazio argiagatik ere (begizta, deiak egiteko).

Adi Shavitek honako hau nabarmentzen du: gaur egun eskuragarri dauden metodoek bilduma osoa zeharkatzen dute eta ez dute barneko tarteko egoera baterako sarbiderik ematen (edo deien itzulketen kasuan egiten dute, baina bigarren mailako efektu desatsegin ugarirekin, Callback Hell adibidez) . Iteratzaileak badaudela dirudi, baina haiekin ere dena ez da hain leuna: ez dago sarrera-irteera puntu komunik (hasi β†’ amaitu versus rbegin β†’ rend eta abar), ez dago argi noiz arte errepikatuko dugun? C++20-tik hasita, arazo hauek konpondu dira!

Lehen aukera: barrutiak. Iteratzaileak bilduz, interfaze komun bat lortzen dugu iterazio baten hasierarako eta amaierarako, eta konposatzeko gaitasuna ere lortzen dugu. Horrek guztiak datuak prozesatzeko kanalizazio osoak eraikitzea errazten du. Baina dena ez da hain leuna: kalkulu-logikaren zati bat iterador zehatz baten inplementazioaren barruan dago, eta horrek kodea ulertzea eta araztea zaildu dezake.

C++ Errusia: nola gertatu zen
Irristatu ΠΏΡ€Π΅Π·Π΅Π½Ρ‚Π°Ρ†ΠΈΠΈ

Bada, kasu honetarako, C++20-k koroutinak gehitu ditu (Python-en sorgailuen antzeko portaera duten funtzioak): exekuzioa atzeratu daiteke uneko balioren bat itzuliz, tarteko egoera mantenduz. Horrela, datuekin agertzen diren moduan lan egiteaz gain, logika guztia korrutina zehatz baten barruan kapsulatzea lortzen dugu.

Baina euli bat dago ukenduan: momentuz, lehendik dauden konpiladoreek partzialki onartzen dituzte, eta, gainera, ez dira nahi bezain txukun inplementatzen: adibidez, oraindik ez du merezi erreferentziak eta aldi baterako objektuak koroutinetan erabiltzea. Gainera, koroutinak izan daitezkeenaren gaineko murrizketa batzuk daude, eta constexpr funtzioak, eraikitzaileak/destruktoreak eta main ez daude zerrenda honetan sartzen.

Horrela, korrutinek arazoen zati esanguratsu bat konpontzen dute datuak prozesatzeko logikaren sinpletasunarekin, baina gaur egungo inplementazioek hobetu egin behar dute.

materialak:

Yandex.Taxi-ren C++ trikimailuak, Anton Polukhin

Nire jarduera profesionaletan, batzuetan gauza osagarri hutsak ezarri behar izaten ditut: barneko interfazearen eta liburutegi batzuen APIaren arteko bilgarri bat, erregistroa edo analisia. Kasu honetan, normalean ez dago optimizazio gehigarririk behar. Baina zer gertatzen da osagai horiek RuNet-eko zerbitzu ezagunenetako batzuetan erabiltzen badira? Egoera horretan, erregistroen orduko terabyte prozesatu beharko dituzu bakarrik! Orduan milisegundo bakoitzak balio du eta, beraz, hainbat trikimailutara jo behar duzu - Anton Polukhinek horietaz hitz egin zuen.

Agian adibiderik interesgarriena pointer-to-implementation (pimpl) ereduaren ezarpena izan zen. 

#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_; 
};

Adibide honetan, lehenik kanpoko liburutegien goiburuko fitxategiak kendu nahi ditut - hau azkarrago konpilatuko da, eta zure burua babestu dezakezu izen-gatazka eta antzeko beste akatsetatik. 

Ados, #include .cpp fitxategira eraman dugu: bildutako APIaren aurrerapen-deklarazioa behar dugu, baita std::unique_ptr ere. Orain esleipen dinamikoak eta beste gauza desatsegin batzuk ditugu, hala nola datuak, datu pila batean sakabanatuta eta berme murriztuak. std::aligned_storage-k guzti honetan lagun dezake. 

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_; 
};

Arazo bakarra: bilgarri bakoitzaren tamaina eta lerrokatzea zehaztu behar dugu - egin dezagun gure pimpl txantiloia parametroekin, erabil ditzagun balio arbitrario batzuk eta gehitu dena ondo asmatu dugun suntsitzaileari egiaztapena. : 

~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"
    ); 
}

Destruktorea prozesatzen denean T dagoeneko definituta dagoenez, kode hau behar bezala analizatuko da eta konpilazio fasean errore gisa sartu behar diren beharrezko tamaina eta lerrokatze balioak aterako ditu. Horrela, konpilazio exekuzio gehigarri baten truke, bildutako klaseen esleipen dinamikoa kentzen dugu, inplementazioarekin batera APIa .cpp fitxategi batean ezkutatzen dugu eta prozesadoreak cachean gordetzeko egokiagoa den diseinua ere lortzen dugu.

Erregistroak eta analisiak ez dira hain ikusgarriak iruditu eta, beraz, ez dira berrikuspen honetan aipatuko.

Txostenaren diapositibak hurrengo estekan daude eskuragarri: ["Taxiko C++ trikimailuak"]

Kodea LEOR mantentzeko teknika modernoak, BjΓΆrn Fahller

Hitzaldi honetan, BjΓΆrn Fahller-ek hainbat modu erakusten ditu behin eta berriz baldintza-kontrolen estilo-akatsari aurre egiteko:

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

Ezaguna zara? Azken estandarretan sartutako C++ teknika indartsu batzuk erabiliz, funtzionalitate bera dotore ezar dezakezu errendimendu zigorrik gabe. Konparatu:   

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

Egiaztapen kopuru finko bat kudeatzeko, berehala erabili behar dituzu txantiloi variadikoak eta tolestu adierazpenak. Demagun enumaren egoera_mota elementuaren hainbat aldagairen berdintasuna egiaztatu nahi dugula. Burura datorkidan lehenengo gauza laguntzaile funtzio bat is_any_of idaztea da:


enum state_type { IDLE, CONNECTED, DISCONNECTED };

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

Tarteko emaitza hau etsigarria da. Orain arte kodea ez da irakurgarriagoa izaten:

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

Mota gabeko txantiloi-parametroek egoera apur bat hobetzen lagunduko dute. Haien laguntzarekin, enumeraren elementu enumeragarriak txantiloiaren parametroen zerrendara transferituko ditugu: 

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

Auto motakoa ez den txantiloi-parametro batean (C++17) erabiliz, ikuspegia konparaketetara orokortzen da, ez bakarrik state_type elementuekin, baita motarik gabeko txantiloi-parametro gisa erabil daitezkeen mota primitiboekin ere:


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

Ondoz ondoko hobekuntza hauen bidez, egiaztapenetarako nahi den sintaxi arina lortzen da:


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);

Adibide honetan, dedukzio-gidak nahi diren egitura-txantiloi-parametroak iradokitzeko balio du konpilatzaileari, honek konstruktorearen argumentu motak ezagutzen dituena. 

Aurrerago - interesgarriagoa. Bjorn-ek ondoriozko kodea nola orokortu irakasten du ==-tik haratago konparazio-operadoreetarako, eta gero eragiketa arbitrarioetarako. Bide horretan, no_unique_address atributua (C++20) eta txantiloi-parametroak lambda funtzioetan (C++20) bezalako ezaugarriak azaltzen dira erabilera adibideak erabiliz. (Bai, orain lambda sintaxia are errazago gogoratzen da - mota guztietako lau parentesi ondoz ondokoak dira.) Funtzioak eraikitzaileen xehetasun gisa erabiltzearen azken irtenbideak benetan berotzen du nire arima, lambda-ren tradizio onenetako tupla esamoldea ahaztu gabe. kalkulua.

Amaieran, ez ahaztu leuntzeaz:

  • Gogoratu lambdak dohainik direla constexpr; 
  • Gehitu dezagun birbidaltze perfektua eta ikus dezagun bere sintaxi itsusiari lambda itxieraren parametro paketeari dagokionez;
  • Eman diezaiogun konpilatzaileari baldintzazko noexcept optimizaziorako aukera gehiago; 
  • Zaindu dezagun txantiloietan errore-irteera ulergarriagoa izatea lambda-ren balio esplizituei esker. Honek konpilatzailea egiaztapen gehiago egitera behartuko du txantiloi-funtzioa benetan deitu aurretik - mota egiaztatzeko fasean. 

Xehetasunetarako, irakurri hitzaldi-materialak: 

Gure inpresioak

Gure lehen parte-hartzea C++ Errusian gogoangarria izan zen bere intentsitateagatik. C++ Errusia gertaera zintzo bat dela iruditu zait, non prestakuntzaren eta zuzeneko komunikazioaren arteko muga ia hautemanezina den. Dena, hizlarien aldartetik hasi eta ekitaldiko bazkideen lehiaketetaraino, eztabaida sutsuetarako aproposa da. Jardunaldiaren edukiak, txostenez osatua, gai nahiko zabala hartzen du, besteak beste, C++ berrikuntzak, proiektu handien kasuak eta arkitektura ideologiko kontuak. Baina bidegabea izango litzateke gertaeraren osagai soziala alde batera uztea, hizkuntza-oztopoak gainditzen laguntzen baitu C++-rekin ez ezik.

Eskerrak eman nahi dizkiegu jardunaldien antolatzaileei horrelako ekitaldi batean parte hartzeko aukeragatik!
Baliteke antolatzaileek C++ Errusiaren iraganari, orainari eta etorkizunari buruzko argitalpena ikusi izana JUG Ru blogean.

Eskerrik asko irakurtzeagatik, eta gure gertaeren berrikuspena lagungarria izatea espero dugu!

Iturria: www.habr.com

Gehitu iruzkin berria