C ++ Russland: wie es war

Wenn Sie zu Beginn des Stücks sagen, dass C ++ - Code an der Wand hängt, sollte er Sie am Ende mit Sicherheit in den Fuß schießen.

Bjarne Stroustrup

Vom 31. Oktober bis 1. November war St. Petersburg Gastgeber der C ++ Russia Piter Conference, einer der größten von der JUG Ru Group organisierten Programmierkonferenzen in Russland. Zu den eingeladenen Rednern gehören Mitglieder des C ++ - Standardisierungskomitees, Redner bei CppCon, Autoren von O'Reilly-Büchern sowie Projektbetreuer wie LLVM, libc ++ und Boost. Die Konferenz richtet sich an erfahrene C ++ - Entwickler, die ihr Fachwissen vertiefen und Erfahrungen in der Live-Kommunikation austauschen möchten. Studenten, Doktoranden und Universitätsprofessoren erhalten sehr angenehme Rabatte.

Die Moskauer Ausgabe der Konferenz kann bereits im April nächsten Jahres besucht werden, aber im Moment werden unsere Studenten Ihnen erzählen, welche interessanten Dinge sie bei der letzten Veranstaltung gelernt haben.



Foto aus dem Konferenzalbum

Über uns


Zwei Studenten der Hochschule für Wirtschaft - St. Petersburg, arbeiteten an diesem Beitrag:

  • Lisa Vasilenko studiert im vierten Studienjahr im Rahmen des Programms „Angewandte Mathematik und Informatik“ die Richtung „Programmiersprachen“. Im ersten Studienjahr mit der C ++ - Sprache vertraut gemacht, anschließend in Praktika in der Industrie Erfahrungen damit gesammelt. Die Leidenschaft für Programmiersprachen im Allgemeinen und die funktionale Programmierung im Besonderen haben ihre Spuren in der Auswahl der Berichte auf der Konferenz hinterlassen.
  • Danya Smirnov studiert im ersten Studienjahr im Masterstudiengang „Datenprogrammierung und -analyse“. Noch in der Schule schrieb er Probleme mit der Olympiade in C ++, und dann kam es irgendwie vor, dass die Sprache in pädagogischen Aktivitäten ständig auftauchte und infolgedessen zur Hauptarbeitssprache wurde. Ich beschloss, an der Konferenz teilzunehmen, um mein Wissen zu erweitern und neue Möglichkeiten kennenzulernen.

Im Newsletter teilen die Leiter der Fakultäten häufig Informationen zu Bildungsveranstaltungen mit Bezug zu unserem Fachgebiet. Im September sahen wir Informationen über C ++ Russia und beschlossen, uns als Zuhörer zu registrieren. Dies ist unsere erste Erfahrung mit der Teilnahme an solchen Konferenzen.

Konferenzstruktur


  • Berichte


Innerhalb von zwei Tagen lasen die Experten 30 Berichte, in denen viele wichtige Themen behandelt wurden: witzige Anwendungen von Sprachfunktionen zur Lösung angewandter Probleme, bevorstehende Sprachupdates aufgrund des neuen Standards, Kompromisse beim C ++ - Design und Vorsichtsmaßnahmen bei der Arbeit mit ihren Konsequenzen, Beispiele für interessante Projektarchitekturen, sowie einige Engine-Teile der Sprachinfrastruktur. Zur gleichen Zeit fanden 3 Vorstellungen statt, meistens zwei in russischer und eine in englischer Sprache.

  • Diskussionszonen


Nach der Rede wurden alle unbeantworteten Fragen und unvollständigen Diskussionen an speziell dafür vorgesehene Kommunikationsbereiche mit Sprechern, die mit Markierungstafeln ausgestattet waren, weitergeleitet. Ein guter Weg, um die Pause zwischen den Auftritten für ein angenehmes Gespräch zu verbringen.

  • Blitzgespräche und informelle Diskussionen


Wenn Sie einen kurzen Bericht verfassen möchten, können Sie sich für einen abendlichen Lightning Talk an einer Pinnwand anmelden und haben fünf Minuten Zeit, um über alles zum Thema der Konferenz zu sprechen. Zum Beispiel eine kurze Einführung in Desinfektionsmittel für C ++ (was sich für einige als neu herausstellte) oder eine Geschichte über einen Fehler bei der Erzeugung einer Sinuskurve, die Sie nur hören, aber nicht sehen können.

Ein weiteres Format ist die Podiumsdiskussion „With the Soul Committee“. Auf der Bühne gibt es einige Mitglieder des Standardisierungskomitees, auf dem Projektor gibt es einen Kamin (offiziell - um eine gefühlvolle Atmosphäre zu schaffen, aber der Grund, "weil ALLES AUF FEUER" lustiger erscheint), die Fragen betreffen den Standard und die allgemeine Vision von C ++, ohne heiße technische Diskussionen und Holivars. Es stellte sich heraus, dass auch lebende Menschen im Ausschuss sitzen, die sich vielleicht nicht ganz sicher sind oder etwas nicht wissen.

Für Holivar-Enthusiasten blieb die dritte Veranstaltung - die BOF-Session „Go against C ++“. Wir nehmen einen Go-Liebhaber, einen C ++ - Liebhaber, vor Beginn der Sitzung bereiten sie zusammen 100500 Folien zum Thema vor (wie Probleme mit Paketen in C ++ oder fehlende Generika in Go), und dann diskutieren sie lebhaft untereinander und mit dem Publikum, und das Publikum versucht, zwei Standpunkte gleichzeitig zu verstehen . Wenn der holivar nicht in Betrieb genommen wird, greift der Moderator ein und versöhnt die Parteien. Dieses Format macht süchtig: Wenige Stunden nach dem Start war nur die Hälfte der Folien fertig. Das Ende musste stark beschleunigt werden.

  • Partner Stände


Die Konferenzpartner waren in den Hallen vertreten - sie sprachen an den Ständen über aktuelle Projekte, boten Praktika und Jobs an, veranstalteten Quiz und kleine Wettbewerbe und spielten auch schöne Preise. Einige Unternehmen boten jedoch sogar an, die ersten Phasen der Befragung zu durchlaufen, was für diejenigen von Nutzen sein kann, die nicht nur Berichte anhören wollten.

Technische Details der Berichte


Wir haben uns beide Tage Berichte angehört. Manchmal war es schwierig, aus den parallel laufenden Berichten einen auszuwählen - wir waren uns einig, das in den Pausen gewonnene Wissen zu teilen und auszutauschen. Trotzdem scheint vieles verloren gegangen zu sein. Hier möchten wir über den Inhalt einiger Berichte sprechen, die uns am interessantesten erschienen

Ausnahmen in C ++ durch das Prisma der Compileroptimierungen, Roman Rusyaev




Präsentationsfolie

Wie der Name schon sagt, untersuchte Roman die Arbeit mit Ausnahmen am Beispiel der LLVM. Gleichzeitig kann der Bericht für diejenigen, die Clang nicht in ihrer Arbeit verwenden, eine Vorstellung davon geben, wie der Code potenziell optimiert werden kann. Dies liegt daran, dass Entwickler von Compilern und entsprechenden Standardbibliotheken miteinander kommunizieren und viele erfolgreiche Lösungen zusammenfallen können.

Um die Ausnahme zu behandeln, müssen Sie viele Aktionen ausführen: Rufen Sie den Verarbeitungscode (falls vorhanden) auf oder setzen Sie Ressourcen auf der aktuellen Ebene frei und wickeln Sie den Stapel höher ab. All dies führt dazu, dass der Compiler zusätzliche Anweisungen für das Auslösen von Aufrufen hinzufügt. Wenn tatsächlich keine Ausnahme verursacht wird, führt das Programm dennoch unnötige Aktionen aus. Um die Gemeinkosten zu senken, verfügt LLVM über verschiedene Heuristiken, mit denen Sie Situationen ermitteln können, in denen Sie keinen Ausnahmebehandlungscode hinzufügen müssen oder die Anzahl der "unnötigen" Anweisungen verringern können.

Der Redner betrachtet etwa ein Dutzend davon und zeigt sowohl Situationen, in denen sie zur Beschleunigung der Programmausführung beitragen, als auch Situationen, in denen diese Methoden nicht anwendbar sind.

So führt Roman Rusyaev die Zuhörer zu dem Schluss, dass Code, der Arbeiten mit Ausnahmen enthält, keinesfalls immer ohne Mehraufwand ausgeführt werden kann, und gibt die folgenden Tipps:

  • Bei der Entwicklung von Bibliotheken sollten Sie grundsätzlich auf Ausnahmen verzichten.
  • Wenn Sie weiterhin Ausnahmen benötigen, sollten Sie nach Möglichkeit Modifikatoren noexcept (und const) hinzufügen, damit der Compiler so weit wie möglich optimieren kann.

Im Allgemeinen bekräftigte der Redner die Auffassung, dass Ausnahmen am besten auf ein Minimum beschränkt oder sogar aufgegeben werden.

Die Berichtsfolien finden Sie unter: [„C ++ - Ausnahmen durch das Prisma der LLVM-Compileroptimierung“]

Generatoren, Koroutinen und andere hirnabbauende Süßigkeiten, Adi Shavit



Präsentationsfolie

Einer der vielen Berichte dieser Konferenz über die Neuerungen von C ++ 20 wurde nicht nur durch seine farbenfrohe Präsentation in Erinnerung gerufen, sondern auch durch die eindeutige Bezeichnung der Probleme mit der Verarbeitungslogik der Sammlung (für Rückrufschleife).

Adi Shavit hebt Folgendes hervor: Derzeit verfügbare Methoden durchlaufen die gesamte Sammlung und gewähren keinen Zugriff auf einen internen Zwischenzustand (oder geben bei Rückrufen, aber mit vielen unangenehmen Nebenwirkungen, wie der gleichen Rückruf-Hölle). Es scheint, dass es Iteratoren gibt, aber bei ihnen ist nicht alles reibungslos: Es gibt keine gemeinsamen Einstiegs- und Ausstiegspunkte (Anfang → Ende versus Anfang → Ende usw.). Es ist unklar, wie oft wir überhaupt iterieren werden. Ab C ++ 20 sind diese Probleme behoben!

Die erste Option: Bereiche. Durch den Wrapper auf Iteratoren erhalten wir eine gemeinsame Schnittstelle für den Beginn und das Ende der Iteration sowie die Möglichkeit der Komposition. All dies macht es einfach, vollwertige Datenverarbeitungs-Pipelines zu erstellen. Aber nicht alles ist so reibungslos: Ein Teil der Berechnungslogik besteht in der Implementierung eines bestimmten Iterators, der den Code für die Wahrnehmung und das Debuggen erschweren kann.


Präsentationsfolie

In diesem Fall wurden in C ++ 20 Coroutinen hinzugefügt (Funktionen, die sich ähnlich wie Generatoren in Python verhalten): Die Ausführung kann verzögert werden, indem ein aktueller Wert zurückgegeben wird, während der Zwischenzustand beibehalten wird. Auf diese Weise arbeiten wir nicht nur mit Daten, wie sie angezeigt werden, sondern kapseln auch die gesamte Logik in einer bestimmten Coroutine.

Die Salbe hat jedoch ein Problem: Momentan werden sie nur teilweise von vorhandenen Compilern unterstützt, und sie werden auch nicht so genau implementiert, wie wir es uns wünschen: Beispielsweise sollten Links und temporäre Objekte nicht in Coroutinen verwendet werden. Außerdem gibt es einige Einschränkungen für mögliche Coroutinen. Constexpr-Funktionen, Konstruktoren / Destruktoren und auch main sind in dieser Liste nicht enthalten.

Somit lösen die Koroutinen einen wesentlichen Teil der Probleme mit der Einfachheit der Datenverarbeitungslogik, aber ihre gegenwärtigen Implementierungen erfordern eine Verfeinerung.

Material:


C ++ Tricks von Yandex.Taxi, Anton Polukhin


In seiner beruflichen Tätigkeit muss man manchmal nur Hilfsdinge implementieren: einen Wrapper zwischen der internen Schnittstelle und der API einer Bibliothek, Protokollierung oder Analyse. In der Regel ist jedoch keine zusätzliche Optimierung erforderlich. Aber was ist, wenn diese Komponenten in einigen der beliebtesten Dienste in Runet verwendet werden? In einer solchen Situation müssen Sie nur Terabyte pro Stunde an Protokollen verarbeiten! Dann zählt jede Millisekunde und deshalb muss man auf verschiedene Tricks zurückgreifen - Anton Polukhin hat darüber gesprochen.

Das vielleicht interessanteste Beispiel war die Implementierung des Pimpl-Musters (Pointer-to-Implementation).

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

In diesem Beispiel möchten Sie zuerst die Header-Dateien externer Bibliotheken entfernen. Sie werden schneller kompiliert und können sich vor möglichen Namenskonflikten und ähnlichen Fehlern schützen.

Ok, #include in die .cpp-Datei verschoben: Sie benötigen die Forward-Deklaration der umschlossenen API sowie std :: unique_ptr. Jetzt haben wir dynamische Zuweisungen und andere unangenehme Dinge, wie Daten, die über einen Haufen verstreut sind, und reduzierte Garantien. Bei alledem kann std :: aligned_storage helfen.

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

Das einzige Problem: Sie müssen die Größe und Ausrichtung für jeden Wrapper angeben - wir erstellen unsere Pimpl-Vorlage mit den Parametern <T, SizeT, AlignmentT>, verwenden einige beliebige Werte und fügen dem Destruktor eine Überprüfung hinzu, dass wir alles erraten haben:

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

Da T bereits während der Verarbeitung des Destruktors definiert wurde, wird dieser Code korrekt analysiert und zeigt in der Kompilierungsphase die erforderlichen Größen- und Ausrichtungswerte an, die in Form von Fehlern eingegeben werden müssen. Auf diese Weise wird auf Kosten eines zusätzlichen Kompilierungsbeginns die dynamische Zuordnung von umschlossenen Klassen aufgehoben, die API in einer CPP-Datei mit der Implementierung ausgeblendet und ein Entwurf erstellt, der für das Caching durch den Prozessor besser geeignet ist.

Protokollierung und Analyse schienen weniger beeindruckend und werden daher in diesem Test nicht erwähnt.

Die Berichtsfolien sind unter folgendem Link verfügbar: [“C ++ Taxi Tricks”]

Moderne Techniken, um Ihren Code trocken zu halten, Björn Fahller


Björn Fahller zeigt in diesem Vortrag verschiedene Möglichkeiten auf, mit Stilfehlern umzugehen, wie beispielsweise wiederholte bedingte Prüfungen:

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

Ist das bekannt Mit mehreren leistungsstarken C ++ - Techniken, die in den letzten Standards verwendet wurden, können Sie dieselbe Funktionalität ohne den geringsten Leistungsverlust ordnungsgemäß implementieren. Vergleichen Sie:

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

Um eine unbegrenzte Anzahl von Schecks zu verarbeiten, werden Sie sofort aufgefordert, verschiedene Vorlagen und Falzausdrücke zu verwenden. Angenommen, wir möchten die Gleichheit mehrerer Variablen mit dem Element enum'a state_type überprüfen. Das erste, was mir in den Sinn kommt, ist, die Hilfsfunktion is_any_of zu schreiben:

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

Ein solches Zwischenergebnis ist enttäuschend. Bisher wird der Code nicht lesbar:

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

Nicht typisierte Vorlagenparameter tragen dazu bei, die Situation ein wenig zu verbessern. Mit ihrer Hilfe übertragen wir die aufgezählten Aufzählungselemente in die Liste der Vorlagenparameter:

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

Bei Verwendung von auto in einem nicht typischen Vorlagenparameter (C ++ 17) wird der Ansatz einfach auf Vergleiche nicht nur mit state_type-Elementen, sondern auch mit primitiven Typen verallgemeinert, die als nicht typisierte Vorlagenparameter verwendet werden können:

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

Durch diese inkrementellen Verbesserungen wird die gewünschte Cursorsyntax für die Überprüfung erreicht:

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

In diesem Beispiel dient der Ableitungsleitfaden dazu, die gewünschten Vorlagenstrukturparameter an einen Compiler weiterzuleiten, der die Typen der Konstruktorargumente kennt.

Interessanter. Björn lehrt, den resultierenden Code zusätzlich zu == für Vergleichsoperatoren und dann für beliebige Operationen zu verallgemeinern. Zusammen mit dem Anwendungsfall werden Funktionen wie das Attribut no_unique_address (C ++ 20) und Vorlagenparameter in Lambda-Funktionen (C ++ 20) erläutert. (Ja, jetzt ist die Lambda-Syntax noch einfacher zu merken - das sind vier aufeinanderfolgende Paare von Klammern aller Art.) Die endgültige Lösung, die Funktionen als Konstruktorteile verwendet, erwärmt meine Seele wirklich, ganz zu schweigen vom Tupelausdruck in den besten Traditionen der Lambda-Rechnung.

Vergessen Sie am Ende nicht, einen Glanz zu setzen:

  • Denken Sie daran, dass Lambdas constexpr kostenlos sind;
  • Fügen Sie eine perfekte Weiterleitung hinzu und sehen Sie sich die hässliche Syntax für das Parameterpaket in Lambda Closure an.
  • Lassen Sie uns dem Compiler mehr Optionen für Optimierungen mit der Bedingung noexcept geben.
  • Aufgrund der expliziten Rückgabewerte von Lambdas sorgen wir für eine deutlichere Fehlerausgabe in Vorlagen. Dadurch wird der Compiler gezwungen, weitere Überprüfungen durchzuführen, bevor die Vorlagenfunktion tatsächlich aufgerufen wird - in der Phase der Typüberprüfung.

Einzelheiten entnehmen Sie bitte den Vorlesungsunterlagen:


Unsere Eindrücke


Unsere erste Teilnahme an C ++ Russia wurde für seinen Reichtum in Erinnerung gerufen. Es gab einen Eindruck von C ++ Russland als emotionales Ereignis, bei dem die Grenze zwischen Lernen und Live-Kommunikation fast nicht erkennbar ist. Alles, von der Stimmung der Redner bis zu den Wettbewerben der Partner der Veranstaltung, ist förderlich für hitzige Diskussionen. Der Inhalt der Konferenz, die aus Berichten besteht, deckt ein ziemlich breites Themenspektrum ab, einschließlich C ++ - Innovationen, Beispielen aus der Praxis großer Projekte und ideologischen architektonischen Überlegungen. Es wäre jedoch unfair, die Aufmerksamkeit der sozialen Komponente der Veranstaltung zu entziehen, was dazu beiträgt, Sprachbarrieren nicht nur in Bezug auf C ++ zu überwinden.

Wir danken den Organisatoren der Konferenz für die Möglichkeit, an einer solchen Veranstaltung teilzunehmen!
Den Beitrag der Organisatoren über Vergangenheit, Gegenwart und Zukunft von C ++ Russia können Sie auf dem JUG Ru-Blog sehen .

Vielen Dank fürs Lesen und wir hoffen, dass sich unsere Nacherzählung der Ereignisse als nützlich erwiesen hat!

Source: https://habr.com/ru/post/de481358/


All Articles