C++ Rusiya: necə oldu

Əgər tamaşanın əvvəlində divarda C++ kodunun asıldığını deyirsənsə, axırda o, səni ayağından vurmağa məcburdur.

Bjarne Stroustrup

Oktyabrın 31-dən noyabrın 1-dək Sankt-Peterburqda “JUG Ru Group”un təşkilatçılığı ilə Rusiyada genişmiqyaslı proqramlaşdırma konfranslarından biri olan C++ Russia Piter konfransı keçirilib. Qonaq məruzəçilərə C++ Standartları Komitəsinin üzvləri, CppCon məruzəçiləri, O'Reilly kitab müəllifləri və LLVM, libc++ və Boost kimi layihələrin baxıcıları daxildir. Konfrans öz təcrübələrini dərinləşdirmək və canlı ünsiyyətdə təcrübə mübadiləsi aparmaq istəyən təcrübəli C++ tərtibatçıları üçün nəzərdə tutulub. Tələbələrə, aspirantlara və universitet müəllimlərinə çox gözəl endirimlər edilir.

Konfransın Moskva nəşrini gələn ilin aprelində ziyarət etmək mümkün olacaq, lakin bu vaxt tələbələrimiz son tədbirdə hansı maraqlı şeyləri öyrəndiklərini sizə xəbər verəcəklər. 

C++ Rusiya: necə oldu

Fotodan konfrans albomu

Haqqımızda

Bu vəzifədə Milli Tədqiqat Universitetinin Ali İqtisadiyyat Məktəbinin - Sankt-Peterburqun iki tələbəsi çalışıb:

  • Liza Vasilenko Tətbiqi Riyaziyyat və Kompüter Elmləri proqramının bir hissəsi kimi Proqramlaşdırma Dilləri üzrə təhsil alan 4-cü kurs bakalavr tələbəsidir. Universitetdə ilk kursda C++ dili ilə tanış olduqdan sonra sənayedə təcrübə keçərək onunla işləmək təcrübəsi qazandım. Ümumilikdə proqramlaşdırma dillərinə və xüsusən də funksional proqramlaşdırmaya olan həvəs konfransda məruzələrin seçimində öz izini buraxdı.
  • Danya Smirnov “Proqramlaşdırma və verilənlərin təhlili” magistr proqramının 1-ci kurs tələbəsidir. Hələ məktəbdə olarkən C++-da olimpiada məsələlərini yazırdım və sonra elə oldu ki, dil daim təhsil fəaliyyətlərində gündəmə gəldi və nəticədə əsas işçi dilə çevrildi. Biliyimi təkmilləşdirmək və həmçinin yeni imkanlar haqqında öyrənmək üçün konfransda iştirak etmək qərarına gəldim.

Bülletendə fakültə rəhbərliyi tez-tez ixtisasımızla bağlı maarifləndirici tədbirlər haqqında məlumat paylaşır. Sentyabr ayında biz C++ Russia haqqında məlumat gördük və dinləyici kimi qeydiyyatdan keçməyə qərar verdik. Bu, bizim belə konfranslarda iştirakla bağlı ilk təcrübəmizdir.

Konfransın strukturu

  • Hesabatlar

İki gün ərzində ekspertlər bir çox aktual mövzuları əhatə edən 30 məruzə oxudular: tətbiq olunan problemlərin həlli üçün dil xüsusiyyətlərindən zəkalı istifadə, yeni standartla əlaqədar dil yeniləmələri, C++ dizaynında güzəştlər və onların nəticələri ilə işləyərkən ehtiyat tədbirləri, nümunələr maraqlı layihə arxitekturası, eləcə də dil infrastrukturunun bəzi gizli detalları. Üç tamaşa eyni vaxtda baş tutdu, əksər hallarda ikisi rus dilində, biri ingilis dilində idi.

  • Müzakirə zonaları

Çıxışdan sonra bütün verilməmiş suallar və yarımçıq müzakirələr spikerlərlə ünsiyyət üçün xüsusi ayrılmış, marker lövhələrlə təchiz olunmuş ərazilərə köçürüldü. Xoş bir söhbətlə çıxışlar arasındakı fasilədən uzaqlaşmağın yaxşı yolu.

  • İldırım danışıqları və qeyri-rəsmi müzakirələr

Qısa hesabat vermək istəyirsinizsə, axşam İldırım Söhbəti üçün lövhədə qeydiyyatdan keçə və konfrans mövzusunda hər hansı bir mövzuda danışmaq üçün beş dəqiqə vaxt əldə edə bilərsiniz. Məsələn, C++ üçün dezinfeksiyaedici maddələrlə qısa tanışlıq (bəziləri üçün bu yeni idi) və ya sinus dalğa nəsilində yalnız eşidilə bilən, lakin görünməyən bir səhv haqqında hekayə.

Digər format “Ürəkdən Ürək Komitəsi ilə” panel müzakirəsidir. Səhnədə standartlaşdırma komitəsinin bəzi üzvləri, proyektorda kamin var (rəsmi olaraq - səmimi atmosfer yaratmaq üçün, lakin "HƏR ŞEY ONDUR" daha gülməli görünür), C++ standartı və ümumi baxışı ilə bağlı suallar. , qızğın texniki müzakirələr və bayramlar olmadan. Məlum oldu ki, komitənin tərkibində nədənsə tam əmin olmayan və ya nəyisə bilməyən canlı insanlar da var.

Holivar həvəskarları üçün üçüncü hadisə işdə qaldı - BOF sessiyası "Go vs. C++". Biz bir Go həvəskarını, C++ həvəskarını götürürük, sessiya başlamazdan əvvəl onlar birlikdə bir mövzuda 100500 slayd hazırlayırlar (məsələn, C++-da paketlərlə bağlı problemlər və ya Go-da generiklərin olmaması) və sonra onlar öz aralarında canlı müzakirə aparırlar və tamaşaçı ilə və tamaşaçı eyni anda iki baxışı anlamağa çalışır. Əgər holivar kontekstdən kənar başlayırsa, moderator müdaxilə edir və tərəfləri barışdırır. Bu format asılılıq yaradır: başlanğıcdan bir neçə saat sonra slaydların yalnız yarısı tamamlandı. Sonu çox sürətləndirmək lazım idi.

  • Tərəfdaş dayanır

Konfransın tərəfdaşları zallarda təmsil olundular - stendlərdə onlar cari layihələrdən danışdılar, təcrübə və iş təklif etdilər, viktorinalar və kiçik müsabiqələr keçirdilər, həmçinin gözəl hədiyyələr oynadılar. Eyni zamanda, bəzi şirkətlər hətta müsahibələrin ilkin mərhələlərini keçməyi təklif etdilər ki, bu da təkcə hesabatları dinləmək üçün gələnlər üçün faydalı ola bilər.

Hesabatların texniki təfərrüatları

Hər iki gün hesabatları dinlədik. Bəzən paralel olanlardan birini seçmək çətin olurdu - biz bölünüb fasilələrdə əldə etdiyimiz bilikləri mübadilə etməyə razılaşdıq. Və buna baxmayaraq, görünür ki, çox şey kənarda qalıb. Burada ən maraqlı hesab etdiyimiz bəzi hesabatların məzmunundan danışmaq istərdik

Kompilyatorun optimallaşdırılması prizmasından C++-da istisnalar, Roman Rusyaev

C++ Rusiya: necə oldu
-dən sürüşdürün təqdimatlar

Başlıqdan göründüyü kimi, Roman nümunə olaraq LLVM istifadə edərək istisnalarla işləməyə baxdı. Eyni zamanda, işlərində Clang-dan istifadə etməyənlər üçün hesabat hələ də kodun necə optimallaşdırıla biləcəyi barədə bir fikir verə bilər. Bunun səbəbi kompilyatorların və müvafiq standart kitabxanaların tərtibatçılarının bir-biri ilə əlaqə saxlaması və bir çox uğurlu həllərin üst-üstə düşə bilməsidir.

Beləliklə, bir istisnanı idarə etmək üçün çox şey etməlisiniz: idarəetmə koduna (əgər varsa) və ya mövcud səviyyədə pulsuz resurslara zəng edin və yığını daha yüksək fırladın. Bütün bunlar ona gətirib çıxarır ki, kompilyator potensial istisnalar yaradan zənglər üçün əlavə təlimatlar əlavə edir. Buna görə də, istisna faktiki olaraq qaldırılmırsa, proqram hələ də lazımsız hərəkətləri yerinə yetirəcəkdir. Əlavə xərcləri azaltmaq üçün LLVM-də istisnalarla işləmə kodunun əlavə edilməsinə ehtiyac olmadığı və ya “əlavə” təlimatların sayının azaldıla biləcəyi vəziyyətləri müəyyən etmək üçün bir neçə evristikaya malikdir.

Natiq onlardan onlarla tədqiq edir və həm proqramın icrasını sürətləndirməyə kömək etdikləri, həm də bu üsulların tətbiq oluna bilməyəcəyi halları göstərir.

Beləliklə, Roman Rusyaev tələbələri belə qənaətə gətirir ki, istisnalarla işləməyi ehtiva edən kodu həmişə sıfır yüklə icra etmək olmaz və aşağıdakı tövsiyələri verir:

  • kitabxanaları inkişaf etdirərkən, prinsipcə istisnalardan imtina etməyə dəyər;
  • əgər istisnalar hələ də lazımdırsa, o zaman mümkün olduqda hər yerdə noexcept (və const) dəyişdiricilərini əlavə etməyə dəyər ki, kompilyator mümkün qədər optimallaşdıra bilsin.

Ümumiyyətlə, natiq istisnaların minimuma endirilməsi və ya tamamilə tərk edilməsi fikrini təsdiqlədi.

Hesabat slaydları ilə aşağıdakı linkdən tanış olmaq olar: [“LLVM kompilyator optimallaşdırmasının obyektivindən C++ istisnaları”]

Generatorlar, korutinlər və digər beyin açan şirinliklər, Adi Şavit

C++ Rusiya: necə oldu
-dən sürüşdürün təqdimatlar

C++ 20-də innovasiyalara həsr olunmuş bu konfransda çoxsaylı məruzələrdən biri təkcə rəngarəng təqdimatı ilə deyil, həm də kolleksiyanın emal məntiqi ilə bağlı mövcud problemlərin (loop, geri çağırışlar üçün) aydın şəkildə müəyyən edilməsi ilə yadda qaldı.

Adi Şavit aşağıdakıları vurğulayır: hazırda mövcud üsullar bütün kolleksiyadan keçir və bəzi daxili aralıq vəziyyətə çıxışı təmin etmir (yaxud onlar geri çağırışlar halında, lakin çoxlu sayda xoşagəlməz yan təsirlərlə, məsələn, Callback Hell) . Deyəsən, iteratorlar var, lakin onlarla belə hər şey o qədər də hamar deyil: ümumi giriş və çıxış nöqtələri yoxdur (başlamaq → son rbegin → rend və s.), nə qədər təkrarlayacağımız bəlli deyil? C++20 ilə başlayaraq bu problemlər həll olunur!

Birinci seçim: diapazonlar. İteratorları bükərək, biz iterasiyanın başlanğıcı və sonu üçün ümumi interfeys əldə edirik və həmçinin tərtib etmək qabiliyyətini əldə edirik. Bütün bunlar tam hüquqlu məlumat emal boru kəmərlərinin qurulmasını asanlaşdırır. Ancaq hər şey o qədər də hamar deyil: hesablama məntiqinin bir hissəsi müəyyən bir iteratorun həyata keçirilməsinin içərisində yerləşir, bu, kodu başa düşmək və sazlamaq üçün çətinləşdirə bilər.

C++ Rusiya: necə oldu
-dən sürüşdürün təqdimatlar

Yaxşı, bu halda, C++20 əlavə koroutinlər (davranışı Python-da generatorlara bənzəyən funksiyalar): aralıq vəziyyəti qoruyarkən bəzi cari dəyəri qaytarmaqla icranı təxirə salmaq olar. Beləliklə, biz yalnız məlumatlarla göründüyü kimi işləməyə deyil, həm də bütün məntiqi müəyyən bir koroutin daxilində əhatə etməyə nail oluruq.

Ancaq məlhəmdə bir milçək var: hazırda onlar mövcud tərtibçilər tərəfindən yalnız qismən dəstəklənir və eyni zamanda istədiyimiz qədər səliqəli şəkildə həyata keçirilmir: məsələn, koroutinlərdə istinadlardan və müvəqqəti obyektlərdən istifadə etməyə hələ dəyməz. Üstəlik, koroutinlər ola biləcək bəzi məhdudiyyətlər var və constexpr funksiyaları, konstruktorlar/dağıdıcılar və əsas bu siyahıya daxil edilməyib.

Beləliklə, koroutinlər verilənlərin emalı məntiqinin sadəliyi ilə bağlı problemlərin əhəmiyyətli hissəsini həll edir, lakin onların cari tətbiqləri təkmilləşdirmə tələb edir.

Materiallar:

Yandex.Taxi, Anton Poluxin-dən C++ fəndləri

Peşəkar fəaliyyətimdə bəzən sırf köməkçi şeylər həyata keçirməli oluram: daxili interfeys və bəzi kitabxananın API-si arasında bir sarğı, giriş və ya təhlil. Bu halda adətən heç bir əlavə optimallaşdırmaya ehtiyac yoxdur. Bəs bu komponentlər RuNet-də ən populyar xidmətlərdən bəzilərində istifadə olunarsa nə olacaq? Belə bir vəziyyətdə, hər saatda terabaytları tək başına işləməli olacaqsınız! Sonra hər millisaniyə sayılır və buna görə də müxtəlif fəndlərə əl atmalısan - Anton Poluxin onlardan danışdı.

Bəlkə də ən maraqlı nümunə göstəricidən icraya (pimpl) nümunəsinin həyata keçirilməsi idi. 

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

Bu nümunədə əvvəlcə xarici kitabxanaların başlıq fayllarından xilas olmaq istəyirəm - bu daha sürətli tərtib ediləcək və özünüzü mümkün ad konfliktlərindən və digər oxşar səhvlərdən qoruya bilərsiniz. 

Yaxşı, biz #include faylını .cpp faylına köçürdük: bizə bükülmüş API-nin, həmçinin std::unique_ptr-nin irəli bəyannaməsi lazımdır. İndi bizdə dinamik ayırmalar və bir dəstə məlumat arasında səpələnmiş məlumatlar və azaldılmış zəmanətlər kimi digər xoşagəlməz şeylər var. std::aligned_storage bütün bunlara kömək edə bilər. 

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

Yeganə problem: hər bir sarğı üçün ölçü və düzülməni təyin etməliyik - gəlin parametrləri ilə pimpl şablonumuzu düzəldək, bəzi ixtiyari dəyərlərdən istifadə edək və dağıdıcıya hər şeyi düzgün təxmin etdiyimizə dair bir çek əlavə edək. : 

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

Destruktoru emal edərkən T artıq müəyyən edildiyi üçün bu kod düzgün təhlil ediləcək və tərtib mərhələsində səhvlər kimi daxil edilməli olan tələb olunan ölçü və hizalanma dəyərlərini çıxaracaqdır. Beləliklə, bir əlavə kompilyasiya qaçışının bahasına biz bükülmüş siniflərin dinamik ayrılmasından xilas oluruq, tətbiqetmə ilə API-ni .cpp faylında gizlədirik, həmçinin prosessor tərəfindən keşləmə üçün daha uyğun dizayn əldə edirik.

Giriş və təhlil daha az təsir edici görünürdü və buna görə də bu baxışda qeyd edilməyəcək.

Hesabat slaydları ilə aşağıdakı linkdən tanış olmaq olar: ["Taksidən C++ hiylələri"]

Kodunuzu DRY saxlamaq üçün müasir üsullar, Björn Fahller

Bu çıxışda Björn Fahller təkrar vəziyyət yoxlamalarının stilistik qüsuru ilə mübarizə aparmaq üçün bir neçə fərqli yol göstərir:

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

Tanış səslənir? Son standartlarda təqdim edilmiş bir neçə güclü C++ texnikasından istifadə etməklə siz eyni funksionallığı heç bir performans cəzası olmadan zərif şəkildə həyata keçirə bilərsiniz. Müqayisə edin:   

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

Qeyri-sabit sayda çekləri idarə etmək üçün dərhal variadik şablonlardan və qat ifadələrindən istifadə etməlisiniz. Fərz edək ki, biz bir neçə dəyişənin enumun state_type elementinə bərabərliyini yoxlamaq istəyirik. Ağla gələn ilk şey köməkçi funksiyanı yazmaqdır 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) || ...); 
}

Bu ara nəticə məyusedicidir. İndiyə qədər kod daha oxunaqlı olmur:

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

Qeyri-növ şablon parametrləri vəziyyəti bir az yaxşılaşdırmağa kömək edəcəkdir. Onların köməyi ilə nömrənin sadalanan elementlərini şablon parametrləri siyahısına köçürəcəyik: 

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

Qeyri-növ şablon parametrində (C++17) avtomatik istifadə etməklə yanaşma sadəcə vəziyyət_tipi elementləri ilə deyil, həm də qeyri-tip şablon parametrləri kimi istifadə oluna bilən primitiv tiplərlə müqayisələri ümumiləşdirir:


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

Bu ardıcıl təkmilləşdirmələr vasitəsilə yoxlamalar üçün istənilən səlis sintaksis əldə edilir:


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

Bu misalda deduksiya təlimatı konstruktor arqumentlərinin növlərini bilən tərtibçiyə istənilən struktur şablonu parametrlərini təklif etməyə xidmət edir. 

Əlavə - daha maraqlı. Byorn nəticə kodunu == xaricində müqayisə operatorları üçün, sonra isə ixtiyari əməliyyatlar üçün ümumiləşdirməyi öyrədir. Yol boyu, no_unique_address atributu (C++20) və lambda funksiyalarındakı şablon parametrləri (C++20) kimi xüsusiyyətlər istifadə nümunələrindən istifadə etməklə izah edilir. (Bəli, indi lambda sintaksisini yadda saxlamaq daha asandır - bunlar bütün növ dörd ardıcıl mötərizə cütüdür.) Konstruktor detalları kimi funksiyalardan istifadə edən son həll, lambdanın ən yaxşı ənənələrindəki ifadə tuple ifadəsini nəzərə almasaq, həqiqətən də ruhumu istiləşdirir. hesablama.

Sonda onu cilalamağı unutmayın:

  • Unutmayın ki, lambdalar pulsuz constexprdir; 
  • Gəlin mükəmməl ekspedisiya əlavə edək və lambda bağlanmasında parametr paketi ilə əlaqədar onun çirkin sintaksisinə baxaq;
  • Gəlin kompilyatora şərti noexcept ilə optimallaşdırmalar üçün daha çox imkanlar verək; 
  • Lambdaların açıq qaytarma dəyərləri sayəsində şablonlarda daha başa düşülən səhv çıxışına diqqət yetirək. Bu, tərtibçini şablon funksiyası həqiqətən çağırılmadan əvvəl daha çox yoxlama aparmağa məcbur edəcək - növün yoxlanılması mərhələsində. 

Ətraflı məlumat üçün mühazirə materiallarına müraciət edin: 

Təəssüratlarımız

C++ Rusiyada ilk iştirakımız öz intensivliyi ilə yadda qaldı. Məndə C++ Rusiyası səmimi bir hadisə kimi təəssürat yaratdı, burada təlimlə canlı ünsiyyət arasındakı sərhəd demək olar ki, hiss olunmur. Natiqlərin əhval-ruhiyyəsindən tutmuş tədbir partnyorlarının yarışlarına qədər hər şey qızğın müzakirələrə şərait yaradır. Məruzələrdən ibarət konfransın məzmunu kifayət qədər geniş mövzuları əhatə edir, o cümlədən C++ innovasiyaları, böyük layihələrin nümunələri və ideoloji memarlıq mülahizələri. Lakin tədbirin təkcə C++ ilə bağlı deyil, dil maneələrini dəf etməyə kömək edən sosial komponentinə məhəl qoymamaq ədalətsizlik olardı.

Belə bir tədbirdə iştirak etmək imkanına görə konfrans təşkilatçılarına təşəkkür edirik!
Siz təşkilatçıların C++ Rusiyasının keçmişi, bu günü və gələcəyi haqqında yazısını görmüş ola bilərsiniz JUG Ru bloqunda.

Oxuduğunuz üçün təşəkkür edirik və ümid edirik ki, hadisələri yenidən izah etmək faydalı oldu!

Mənbə: www.habr.com

Добавить комментарий