C++ Russia: paano ito nangyari

Kung sa simula ng dula ay sasabihin mo na mayroong C++ code na nakasabit sa dingding, pagkatapos ay sa dulo ay tiyak na babarilin ka nito sa paa.

Bjarne Stroustrup

Mula Oktubre 31 hanggang Nobyembre 1, ang C++ Russia Piter conference ay ginanap sa St. Petersburg - isa sa mga malakihang programming conference sa Russia, na inorganisa ng JUG Ru Group. Kasama sa mga guest speaker ang mga miyembro ng C++ Standards Committee, CppCon speakers, O'Reilly book authors, at maintainers ng mga proyekto gaya ng LLVM, libc++, at Boost. Ang kumperensya ay naglalayon sa mga may karanasang C++ developer na gustong palalimin ang kanilang kadalubhasaan at makipagpalitan ng mga karanasan sa live na komunikasyon. Ang mga mag-aaral, nagtapos na mga mag-aaral at mga guro sa unibersidad ay binibigyan ng napakagandang mga diskwento.

Ang edisyon ng Moscow ng kumperensya ay magagamit upang bisitahin sa unang bahagi ng Abril sa susunod na taon, ngunit pansamantala ang aming mga mag-aaral ay sasabihin sa iyo kung ano ang mga kagiliw-giliw na bagay na natutunan nila sa huling kaganapan. 

C++ Russia: paano ito nangyari

Larawan mula sa album ng kumperensya

Tungkol sa amin

Dalawang estudyante mula sa National Research University Higher School of Economics - St. Petersburg ang nagtrabaho sa post na ito:

  • Si Liza Vasilenko ay isang 4th year undergraduate na estudyante na nag-aaral ng Programming Languages ​​​​bilang bahagi ng Applied Mathematics and Computer Science program. Dahil nakilala ko ang wikang C++ sa aking unang taon sa unibersidad, nagkaroon ako ng karanasan sa pagtatrabaho dito sa pamamagitan ng mga internship sa industriya. Ang aking pagkahilig sa mga programming language sa pangkalahatan at functional programming sa partikular ay nag-iwan ng marka sa pagpili ng mga ulat sa kumperensya.
  • Si Danya Smirnov ay isang 1st year student ng master's program na "Programming and Data Analysis". Habang nasa paaralan pa, nagsulat ako ng mga problema sa Olympiad sa C++, at pagkatapos ay nangyari na ang wika ay patuloy na lumalabas sa mga aktibidad na pang-edukasyon at kalaunan ay naging pangunahing wikang gumagana. Nagpasya akong lumahok sa kumperensya upang mapabuti ang aking kaalaman at malaman din ang tungkol sa mga bagong pagkakataon.

Sa newsletter, madalas na nagbabahagi ang pamunuan ng faculty ng impormasyon tungkol sa mga kaganapang pang-edukasyon na nauugnay sa aming espesyalidad. Noong Setyembre nakakita kami ng impormasyon tungkol sa C++ Russia at nagpasyang magparehistro bilang mga tagapakinig. Ito ang aming unang karanasan sa paglahok sa mga naturang kumperensya.

Istruktura ng kumperensya

  • Mga ulat

Sa loob ng dalawang araw, nagbasa ang mga eksperto ng 30 ulat, na sumasaklaw sa maraming maiinit na paksa: mapanlikhang paggamit ng mga feature ng wika upang malutas ang mga inilapat na problema, paparating na mga update sa wika kaugnay ng bagong pamantayan, mga kompromiso sa disenyo ng C++ at mga pag-iingat kapag gumagawa ng mga kahihinatnan nito, mga halimbawa ng kawili-wiling arkitektura ng proyekto, pati na rin ang ilang detalye ng under-the-hood ng imprastraktura ng wika. Tatlong pagtatanghal ang naganap nang sabay-sabay, kadalasang dalawa sa Russian at isa sa Ingles.

  • Mga zone ng talakayan

Pagkatapos ng talumpati, ang lahat ng hindi naitanong at hindi natapos na mga talakayan ay inilipat sa mga espesyal na itinalagang lugar para sa komunikasyon sa mga nagsasalita, na nilagyan ng mga marker board. Isang magandang paraan upang mapawi ang pahinga sa pagitan ng mga talumpati na may kaaya-ayang pag-uusap.

  • Mga Usapang Kidlat at mga impormal na talakayan

Kung gusto mong magbigay ng maikling ulat, maaari kang mag-sign up sa whiteboard para sa Lightning Talk sa gabi at makakuha ng limang minutong oras upang pag-usapan ang anumang bagay sa paksa ng kumperensya. Halimbawa, isang mabilis na pagpapakilala sa mga sanitizer para sa C++ (para sa ilan ay bago ito) o isang kuwento tungkol sa isang bug sa pagbuo ng sine wave na maririnig lang, ngunit hindi nakikita.

Ang isa pang format ay ang panel discussion na β€œWith a Heart to Heart Committee.” Sa entablado ay ilang miyembro ng komite ng standardisasyon, sa projector ay isang fireplace (opisyal - upang lumikha ng isang taos-puso na kapaligiran, ngunit ang dahilan "dahil ANG LAHAT AY NASUNOG" ay tila mas nakakatawa), mga tanong tungkol sa pamantayan at pangkalahatang pananaw ng C++ , nang walang mainit na teknikal na talakayan at holiwar. Lumalabas na naglalaman din ang komite ng mga buhay na tao na maaaring hindi lubos na sigurado sa isang bagay o maaaring hindi alam ang isang bagay.

Para sa mga tagahanga ng holivar, nanatili ang ikatlong kaganapan sa kaso - ang BOF session na "Go vs. C++". Kumuha kami ng Go lover, isang C++ lover, bago magsimula ang session, magkasama silang naghahanda ng 100500 slide sa isang paksa (tulad ng mga problema sa mga package sa C++ o kakulangan ng generics sa Go), at pagkatapos ay mayroon silang masiglang talakayan sa kanilang mga sarili at kasama ng madla, at sinusubukan ng madla na maunawaan ang dalawang punto ng pananaw nang sabay-sabay . Kung ang isang holivar ay magsisimula sa labas ng konteksto, ang moderator ay mamagitan at ipagkasundo ang mga partido. Nakakahumaling ang format na ito: ilang oras pagkatapos ng simula, kalahati lang ng mga slide ang nakumpleto. Ang wakas ay kailangang lubos na mapabilis.

  • Tumayo ang partner

Ang mga kasosyo ng kumperensya ay kinatawan sa mga bulwagan - sa mga stand ay pinag-usapan nila ang tungkol sa mga kasalukuyang proyekto, nag-aalok ng mga internship at trabaho, nagsagawa ng mga pagsusulit at maliliit na kumpetisyon, at nag-raffle din ng magagandang premyo. Kasabay nito, nag-alok pa ang ilang kumpanya na dumaan sa mga unang yugto ng mga panayam, na maaaring maging kapaki-pakinabang para sa mga dumating hindi lamang upang makinig sa mga ulat.

Mga teknikal na detalye ng mga ulat

Nakinig kami sa mga ulat sa dalawang araw. Minsan mahirap pumili ng isang ulat mula sa magkatulad na mga ulat - napagkasunduan naming maghiwalay at makipagpalitan ng kaalamang natamo sa mga pahinga. At gayunpaman, tila marami ang naiwan. Dito gusto naming pag-usapan ang mga nilalaman ng ilan sa mga ulat na nakita naming pinakakawili-wili

Mga pagbubukod sa C++ sa pamamagitan ng prisma ng compiler optimizations, Roman Rusyaev

C++ Russia: paano ito nangyari
Slide mula sa mga pagtatanghal

Tulad ng iminumungkahi ng pamagat, tiningnan ni Roman ang pagtatrabaho nang may mga pagbubukod gamit ang LLVM bilang isang halimbawa. Kasabay nito, para sa mga hindi gumagamit ng Clang sa kanilang trabaho, ang ulat ay maaari pa ring magbigay ng ilang ideya kung paano maaaring ma-optimize ang code. Ito ay dahil ang mga nag-develop ng mga compiler at kaukulang karaniwang mga aklatan ay nakikipag-usap sa isa't isa at maraming matagumpay na solusyon ang maaaring magkasabay.

Kaya, upang mahawakan ang isang pagbubukod, kailangan mong gumawa ng maraming bagay: tawagan ang handling code (kung mayroon man) o mga libreng mapagkukunan sa kasalukuyang antas at paikutin ang stack nang mas mataas. Ang lahat ng ito ay humahantong sa katotohanan na ang compiler ay nagdaragdag ng mga karagdagang tagubilin para sa mga tawag na posibleng magtapon ng mga pagbubukod. Samakatuwid, kung ang pagbubukod ay hindi aktwal na itinaas, ang programa ay magsasagawa pa rin ng mga hindi kinakailangang aksyon. Upang kahit papaano ay mabawasan ang overhead, ang LLVM ay may ilang heuristics para sa pagtukoy ng mga sitwasyon kung saan ang exception handling code ay hindi kailangang idagdag o ang bilang ng "dagdag" na mga tagubilin ay maaaring bawasan.

Sinusuri ng tagapagsalita ang tungkol sa isang dosenang mga ito at ipinapakita ang parehong mga sitwasyon kung saan nakakatulong ang mga ito na pabilisin ang pagpapatupad ng programa, at ang mga kung saan hindi naaangkop ang mga pamamaraang ito.

Kaya, pinangunahan ni Roman Rusyaev ang mga mag-aaral sa konklusyon na ang code na naglalaman ng exception handling ay hindi maaaring palaging maisakatuparan nang walang overhead, at nagbibigay ng sumusunod na payo:

  • kapag bumubuo ng mga aklatan, sulit na iwanan ang mga pagbubukod sa prinsipyo;
  • kung kailangan pa rin ang mga pagbubukod, kung gayon hangga't maaari ay sulit na magdagdag ng noexcept (at const) na mga modifier sa lahat ng dako upang ang compiler ay makapag-optimize hangga't maaari.

Sa pangkalahatan, kinumpirma ng tagapagsalita ang pananaw na ang mga pagbubukod ay pinakamahusay na ginagamit sa pinakamababa o ganap na inabandona.

Ang mga slide ng ulat ay makukuha sa sumusunod na link: [β€œC++ exceptions through the lens of LLVM compiler optimizations”]

Mga generator, coroutine at iba pang tamis na nakakapagpalabas ng utak, Adi Shavit

C++ Russia: paano ito nangyari
Slide mula sa mga pagtatanghal

Ang isa sa maraming ulat sa kumperensyang ito na nakatuon sa mga inobasyon sa C++20 ay hindi malilimutan hindi lamang para sa makulay na pagtatanghal nito, kundi pati na rin para sa malinaw nitong pagkakakilanlan ng mga kasalukuyang problema sa lohika sa pagproseso ng koleksyon (para sa loop, mga callback).

Itinatampok ng Adi Shavit ang mga sumusunod: ang kasalukuyang magagamit na mga pamamaraan ay dumaan sa buong koleksyon at hindi nagbibigay ng access sa ilang panloob na intermediate na estado (o ginagawa nila sa kaso ng mga callback, ngunit may malaking bilang ng mga hindi kasiya-siyang epekto, tulad ng Callback Hell) . Mukhang may mga iterator, ngunit kahit na sa kanila ang lahat ay hindi masyadong maayos: walang mga karaniwang entry at exit point (simula β†’ end versus rbegin β†’ rend at iba pa), hindi malinaw kung gaano katagal tayo mag-uulit? Simula sa C++20, malulutas ang mga problemang ito!

Unang pagpipilian: mga saklaw. Sa pamamagitan ng pag-wrap ng mga iterator, nakakakuha kami ng karaniwang interface para sa simula at pagtatapos ng isang pag-ulit, at nakakakuha din kami ng kakayahang mag-compose. Ang lahat ng ito ay nagpapadali sa pagbuo ng ganap na mga pipeline sa pagproseso ng data. Ngunit hindi lahat ay napakakinis: bahagi ng lohika ng pagkalkula ay matatagpuan sa loob ng pagpapatupad ng isang partikular na iterator, na maaaring makapagpalubha ng code upang maunawaan at ma-debug.

C++ Russia: paano ito nangyari
Slide mula sa mga pagtatanghal

Well, para sa kasong ito, nagdagdag ang C++20 ng mga coroutine (mga function na ang pag-uugali ay katulad ng mga generator sa Python): maaaring ipagpaliban ang pagpapatupad sa pamamagitan ng pagbabalik ng ilang kasalukuyang halaga habang pinapanatili ang isang intermediate na estado. Kaya, nakakamit namin hindi lamang ang pagtatrabaho sa data tulad ng lumilitaw, kundi pati na rin ang pag-encapsulate ng lahat ng lohika sa loob ng isang partikular na coroutine.

Ngunit mayroong isang langaw sa pamahid: sa sandaling ito ay bahagyang sinusuportahan lamang ng mga umiiral na compiler, at hindi rin ipinatupad nang maayos tulad ng gusto natin: halimbawa, hindi pa sulit ang paggamit ng mga sanggunian at pansamantalang mga bagay sa mga coroutine. Dagdag pa, mayroong ilang mga paghihigpit sa kung ano ang maaaring maging mga coroutine, at ang mga function ng constexpr, constructor/destructors, at pangunahing ay hindi kasama sa listahang ito.

Kaya, malulutas ng mga coroutine ang isang makabuluhang bahagi ng mga problema sa pagiging simple ng lohika sa pagproseso ng data, ngunit ang kanilang kasalukuyang mga pagpapatupad ay nangangailangan ng pagpapabuti.

Mga Materyales:

Mga trick ng C++ mula sa Yandex.Taxi, Anton Polukhin

Sa aking mga propesyonal na aktibidad, minsan kailangan kong magpatupad ng mga pantulong na bagay: isang wrapper sa pagitan ng panloob na interface at ng API ng ilang library, pag-log o pag-parse. Sa kasong ito, karaniwang hindi na kailangan para sa anumang karagdagang pag-optimize. Ngunit paano kung ang mga sangkap na ito ay ginagamit sa ilan sa mga pinakasikat na serbisyo sa RuNet? Sa ganoong sitwasyon, kakailanganin mong magproseso ng mga terabytes kada oras ng mga log nang mag-isa! Pagkatapos ang bawat millisecond ay binibilang at samakatuwid ay kailangan mong gumamit ng iba't ibang mga trick - pinag-usapan sila ni Anton Polukhin.

Marahil ang pinakakawili-wiling halimbawa ay ang pagpapatupad ng pattern ng 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_; 
};

Sa halimbawang ito, gusto ko munang alisin ang mga file ng header ng mga panlabas na aklatan - mas mabilis itong mag-compile, at mapoprotektahan mo ang iyong sarili mula sa posibleng mga salungatan sa pangalan at iba pang katulad na mga error. 

Okay, inilipat namin ang #include sa .cpp file: kailangan namin ng forward-declaration ng nakabalot na API, pati na rin ang std::unique_ptr. Ngayon ay mayroon na kaming mga dynamic na alokasyon at iba pang hindi kasiya-siyang bagay tulad ng data na nakakalat sa isang bungkos ng data at pinababang mga garantiya. std::aligned_storage ay maaaring makatulong sa lahat ng ito. 

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

Ang tanging problema: kailangan mong tukuyin ang laki at pagkakahanay para sa bawat wrapper - gawin natin ang aming pimpl template na may mga parameter , gumamit ng ilang di-makatwirang halaga at magdagdag ng tseke sa destructor na nakuha namin ang lahat ng tama: 

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

Dahil ang T ay tinukoy na kapag pinoproseso ang destructor, ang code na ito ay mai-parse nang tama at sa yugto ng compilation ay ilalabas nito ang kinakailangang laki at mga halaga ng pagkakahanay na kailangang ilagay bilang mga error. Kaya, sa halaga ng isang karagdagang compilation run, inaalis namin ang dynamic na alokasyon ng mga nakabalot na klase, itago ang API sa isang .cpp file na may pagpapatupad, at kumuha din ng disenyo na mas angkop para sa pag-cache ng processor.

Ang pag-log at pag-parse ay tila hindi gaanong kahanga-hanga at samakatuwid ay hindi babanggitin sa pagsusuri na ito.

Ang mga slide ng ulat ay makukuha sa sumusunod na link: ["C++ tricks from Taxi"]

Mga modernong pamamaraan para sa pagpapanatiling DRY ng iyong code, BjΓΆrn Fahller

Sa pahayag na ito, ipinakita ni BjΓΆrn Fahller ang ilang iba't ibang paraan upang labanan ang estilistang depekto ng paulit-ulit na pagsusuri sa kundisyon:

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

Parang pamilyar? Sa pamamagitan ng paggamit ng ilang makapangyarihang diskarte sa C++ na ipinakilala sa mga kamakailang pamantayan, maaari mong eleganteng ipatupad ang parehong functionality nang walang anumang parusa sa pagganap. Ihambing:   

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

Upang mahawakan ang isang hindi nakapirming bilang ng mga tseke, kailangan mong gumamit kaagad ng mga variadic na template at fold expression. Ipagpalagay natin na gusto nating suriin ang pagkakapantay-pantay ng ilang variable sa state_type na elemento ng enum. Ang unang bagay na pumapasok sa isip ay ang magsulat ng isang helper function 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) || ...); 
}

Nakakadismaya ang intermediate na resultang ito. Sa ngayon ang code ay hindi nagiging mas nababasa:

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

Ang mga parameter na hindi uri ng template ay makakatulong na mapabuti ang sitwasyon nang kaunti. Sa kanilang tulong, ililipat namin ang mga enumerable na elemento ng enum sa listahan ng mga parameter ng template: 

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

Sa pamamagitan ng paggamit ng auto sa isang non-type na parameter ng template (C++17), ang diskarte ay nagsa-generalize lamang sa mga paghahambing hindi lamang sa state_type na mga elemento, kundi pati na rin sa mga primitive na uri na maaaring gamitin bilang hindi uri ng mga parameter ng template:


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

Sa pamamagitan ng sunud-sunod na pagpapahusay na ito, nakakamit ang nais na matatas na syntax para sa mga pagsusuri:


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

Sa halimbawang ito, ang gabay sa pagbabawas ay nagsisilbing magmungkahi ng nais na mga parameter ng template ng istraktura sa compiler, na nakakaalam ng mga uri ng mga argumento ng constructor. 

Dagdag pa - mas kawili-wili. Itinuro ni Bjorn kung paano i-generalize ang resultang code para sa mga operator ng paghahambing na lampas sa ==, at pagkatapos ay para sa mga arbitrary na operasyon. Kasabay nito, ang mga feature tulad ng no_unique_address attribute (C++20) at mga parameter ng template sa mga function ng lambda (C++20) ay ipinapaliwanag gamit ang mga halimbawa ng paggamit. (Oo, ngayon ang lambda syntax ay mas madaling matandaan - ito ay apat na magkakasunod na pares ng panaklong sa lahat ng uri.) Ang pangwakas na solusyon gamit ang mga function bilang mga detalye ng constructor ay talagang nagpapainit sa aking kaluluwa, hindi banggitin ang expression na tuple sa pinakamahusay na mga tradisyon ng lambda calculus.

Sa dulo, huwag kalimutang pakinisin ito:

  • Tandaan na ang mga lambdas ay constexpr nang libre; 
  • Magdagdag tayo ng perpektong pagpapasa at tingnan ang pangit na syntax nito kaugnay ng parameter pack sa pagsasara ng lambda;
  • Bigyan natin ang compiler ng mas maraming pagkakataon para sa mga optimization na may kondisyon na noexcept; 
  • Alagaan natin ang mas nauunawaang output ng error sa mga template salamat sa tahasang mga halaga ng pagbabalik ng mga lambdas. Pipilitin nito ang compiler na gumawa ng higit pang mga pagsusuri bago aktwal na tawagin ang function ng template - sa yugto ng pagsuri ng uri. 

Para sa mga detalye, mangyaring sumangguni sa mga materyales sa panayam: 

Ang aming mga impression

Ang aming unang paglahok sa C++ Russia ay hindi malilimutan para sa intensity nito. Nakuha ko ang impresyon ng C++ Russia bilang isang taos-pusong kaganapan, kung saan ang linya sa pagitan ng pagsasanay at live na komunikasyon ay halos hindi mahahalata. Ang lahat, mula sa mood ng mga tagapagsalita hanggang sa mga kumpetisyon mula sa mga kasosyo sa kaganapan, ay nakakatulong sa mainit na mga talakayan. Ang nilalaman ng kumperensya, na binubuo ng mga ulat, ay sumasaklaw sa medyo malawak na hanay ng mga paksa kabilang ang mga pagbabago sa C++, case study ng malalaking proyekto at mga pagsasaalang-alang sa ideolohikal na arkitektura. Ngunit magiging hindi patas na huwag pansinin ang panlipunang bahagi ng kaganapan, na tumutulong sa pagtagumpayan ang mga hadlang sa wika na may kaugnayan hindi lamang sa C++.

Nagpapasalamat kami sa mga organizer ng kumperensya para sa pagkakataong lumahok sa naturang kaganapan!
Maaaring nakita mo na ang post ng mga organizer tungkol sa nakaraan, kasalukuyan at hinaharap ng C++ Russia sa JUG Ru blog.

Salamat sa pagbabasa, at umaasa kaming nakatulong ang aming muling pagsasalaysay ng mga kaganapan!

Pinagmulan: www.habr.com

Magdagdag ng komento