Der Autor des Materials, dessen Übersetzung wir heute veröffentlichen, sagt, dass sich C ++ in seiner modernen Form im Vergleich zu dieser Sprache vor einigen Jahren erheblich zum Besseren verändert hat. Natürlich sind diese Änderungen nicht sofort eingetreten. In früheren Zeiten fehlte C ++ beispielsweise die Dynamik. Es war nicht leicht, eine Person zu finden, die sagen konnte, dass sie zärtliche Gefühle für diese Sprache hat. Alles änderte sich, als diejenigen, die für die Standardisierung der Sprache verantwortlich sind, beschlossen, Innovationen Platz zu machen. Im Jahr 2011 wurde C ++ eine dynamische Sprache, eine Sprache, die sich ständig weiterentwickelt und Programmierer viel positivere Emotionen hervorruft.
Denken Sie nicht, dass die Sprache einfacher geworden ist. Es kann immer noch als eine der komplexesten, weit verbreiteten Programmiersprachen bezeichnet werden, wenn nicht sogar als die komplexeste. Aber modernes C ++ ist viel freundlicher geworden als zuvor.

Heute werden wir über einige der neuen Funktionen der Sprache sprechen (beginnend mit C ++ 11, das übrigens bereits 8 Jahre alt ist), die für jeden Programmierer nützlich sein werden.
Auto-Schlüsselwort
Seit das
auto
Schlüsselwort in C ++ 11 vorkommt, ist das Leben von Programmierern einfacher geworden. Dank dieses Schlüsselworts kann der Compiler zur Kompilierungszeit Variablentypen ausgeben, sodass wir nicht immer selbst Typen angeben müssen. Dies hat sich beispielsweise in Fällen als sehr praktisch erwiesen, in denen Sie mit Datentypen wie
map<string,vector<pair<int,int>>>
. Bei der Verwendung des Schlüsselworts
auto
sind einige Dinge zu beachten. Betrachten Sie ein Beispiel:
auto an_int = 26;
Achten Sie auf die letzte Zeile in diesem Beispiel, deren Kommentar als
#1
markiert ist (im Folgenden werden wir auf ähnliche Weise die Zeilen markieren, die wir nach den Beispielen analysieren werden). In dieser Zeile befindet sich kein Initialisierer. Sie können dies nicht tun. Der Code in dieser Zeile verhindert, dass der Compiler den Typ der entsprechenden Variablen kennt.
Anfangs war das
auto
Schlüsselwort in C ++ ziemlich begrenzt. In neueren Versionen der Sprache wurden dann
auto
Funktionen hinzugefügt. Hier ist ein weiteres Beispiel:
auto merge(auto a, auto b)
Die Zeilen
#1
und
#2
wenden die Variableninitialisierung mit geschweiften Klammern an - eine weitere neue Funktion in C ++ 11.
Denken Sie daran, dass der Compiler bei Verwendung des Schlüsselworts
auto
eine Möglichkeit haben muss, auf den Typ der Variablen zu schließen.
Nun eine interessante Frage. Was passiert, wenn Sie ein Design wie
auto a = {1, 2, 3}
? Was ist das? Vektor oder Ursache für Kompilierungsfehler?
Tatsächlich wurde in C ++ 11 eine Konstruktion der Form
std::initializer_list<type>
angezeigt. Die Liste der Initialisierungswerte in Klammern wird mit dem Schlüsselwort
auto
als Container behandelt.
Und schließlich kann, wie bereits erwähnt, die Typinferenz durch den Compiler äußerst nützlich sein, wenn Sie mit komplexen Datenstrukturen arbeiten müssen. Hier ist ein Beispiel:
void populate(auto &data) {
Schauen Sie sich Zeile
#1
. Der Ausdruck
auto [v1,v2] = itr.second
stellt eine neue Funktion von C ++ 17 dar. Dies ist die sogenannte Zerlegung beim Deklarieren von Variablen. In früheren Versionen der Sprache musste jeder Wert einzeln extrahiert werden. Dank dieses Mechanismus ist das Ausführen solcher Operationen viel bequemer geworden.
Wenn Sie mit Daten über Links arbeiten müssen, reicht es außerdem aus, dieser Konstruktion nur ein Zeichen hinzuzufügen und es in die folgende Form zu konvertieren:
auto &[v1,v2] = itr.second
.
Lambda-Ausdrücke
C ++ 11 bietet Unterstützung für Lambda-Ausdrücke. Sie ähneln anonymen Funktionen in JavaScript und können mit Funktionsobjekten ohne Namen verglichen werden. Sie erfassen Variablen in verschiedenen Bereichen, abhängig von ihrer Beschreibung, für die kompakte syntaktische Konstruktionen verwendet werden. Außerdem können sie Variablen zugeordnet werden.
Lambda-Ausdrücke sind ein sehr nützliches Werkzeug für Fälle, in denen Sie eine kleine Operation im Code ausführen müssen, aber keine separate Funktion dafür schreiben möchten. Ein weiteres häufiges Beispiel für ihre Verwendung ist die Erstellung von Funktionen zum Vergleichen von Werten. Zum Beispiel:
std::vector<std::pair<int,int>> data = {{1,3}, {7,6}, {12, 4}};
In diesem kurzen Beispiel finden Sie viele interessante Dinge.
Achten Sie zunächst darauf, wie bequem es ist, die variable Initialisierung mit geschweiften Klammern zu verwenden. Als nächstes sehen wir die Standardkonstruktionen
begin()
und
end()
, die auch in C ++ 11 erschienen sind. Dann kommt die Lambda-Funktion, die als Mechanismus zum Vergleichen von Daten verwendet wird. Die Parameter dieser Funktion werden mit dem Schlüsselwort
auto
deklariert. Diese Funktion wurde in C ++ 14 angezeigt. Bisher konnte dieses Schlüsselwort nicht zur Beschreibung der Funktionsparameter verwendet werden.
Beachten Sie nun, dass der Lambda-Ausdruck mit eckigen Klammern beginnt -
[]
. Dies ist die sogenannte Variablenmaske. Es bestimmt den Umfang des Ausdrucks, dh Sie können die Beziehung des Lambda-Ausdrucks zu lokalen Variablen und Objekten steuern.
Hier ist ein Auszug aus
diesem Repository, das modernen C ++ - Funktionen gewidmet ist:
[]
- Der Ausdruck erfasst nichts. Dies bedeutet, dass es in einem Lambda-Ausdruck unmöglich ist, lokale Variablen aus dem externen Bereich zu verwenden. Im Ausdruck können nur Parameter verwendet werden.[=]
- Der Ausdruck erfasst die Werte lokaler Objekte (dh lokaler Variablen, Parameter). Dies bedeutet, dass sie verwendet, aber nicht geändert werden können.[&]
- Der Ausdruck erfasst Verweise auf lokale Objekte. Sie können wie im folgenden Beispiel gezeigt geändert werden.[this]
- Der Ausdruck erfasst den Wert this
Zeigers.[a, &b]
- Der Ausdruck erfasst den Wert von Objekt a
und einen Verweis auf Objekt b
.
Wenn Sie innerhalb der Lambda-Funktion die Daten in ein anderes Format konvertieren müssen, können Sie die oben genannten Mechanismen verwenden. Betrachten Sie ein Beispiel:
std::vector<int> data = {2, 4, 4, 1, 1, 3, 9}; int factor = 7; for_each(begin(data), end(data), [&factor](int &val) {
Wenn hier auf die
factor
nach Wert zugegriffen wurde (dann würde die Variablenmaske
[factor]
verwendet, um den Lambda-Ausdruck zu beschreiben), konnte der
factor
in Zeile
#1
nicht geändert werden - einfach, weil wir keine Rechte dazu hätten Durchführen einer solchen Operation. In diesem Beispiel haben wir das Recht auf solche Aktionen. In solchen Situationen ist es wichtig, die Funktionen, die Zugriffsvariablen als Referenz bereitstellen, nicht zu missbrauchen.
Beachten Sie außerdem, dass auf
val
auch als Referenz zugegriffen wird. Dies stellt sicher, dass Datenänderungen, die in der Lambda-Funktion auftreten, den
vector
beeinflussen.
Variable Initialisierungsausdrücke in if- und switch-Konstrukten
Diese C ++ 17-Innovation hat mir sehr gut gefallen, nachdem ich davon erfahren hatte. Betrachten Sie ein Beispiel:
std::set<int> input = {1, 5, 3, 6}; if(auto it = input.find(7); it==input.end()){
Es stellt sich heraus, dass Sie jetzt die Variablen initialisieren und mit ihrer Verwendung in einem
if
oder
switch
Block vergleichen können. Dies hilft, genauen Code zu schreiben. Hier ist eine schematische Beschreibung der betrachteten Struktur:
if( init-statement(x); condition(x)) {
Durchführen von Berechnungen zur Kompilierungszeit mit constexpr
Das
constexpr
bietet uns großartige Möglichkeiten. Angenommen, wir haben eine Art Ausdruck, der berechnet werden muss, während sich sein Wert nach dem Initialisieren mit der entsprechenden Variablen nicht ändert. Ein solcher Ausdruck kann im Voraus berechnet und als Makro verwendet werden. Oder, was in C ++ 11 möglich wurde, verwenden Sie das
constexpr
.
Programmierer bemühen sich, den Rechenaufwand während der Programmausführung zu minimieren. Wenn bestimmte Vorgänge während des Kompilierungsprozesses ausgeführt werden können und dadurch die Last aus dem System während der Programmausführung entfernt wird, hat dies einen guten Einfluss auf das Verhalten des Programms während der Ausführung. Hier ist ein Beispiel:
#include <iostream> constexpr long long fact(long long n) { // constexpr return n == 1 ? 1 : (fact(n-1) * n); } int main() { const long long bigval = fact(20); std::cout<<bigval<<std::endl; }
Dies ist ein sehr häufiges Beispiel für die Verwendung von
constexpr
.
Da wir die Funktion zur Berechnung der Fakultät als
constexpr
, kann der Compiler den
constexpr
fact(20)
zum Zeitpunkt der Kompilierung des Programms vorberechnen. Infolgedessen ist nach der Kompilierung der String
const long long bigval = fact(20);
kann durch
const long long bigval = 2432902008176640000;
.
Beachten Sie, dass das an die Funktion übergebene Argument durch eine Konstante dargestellt wird. Dies ist eine wichtige Funktion bei der Verwendung von Funktionen, die mit dem
constexpr
. Die an sie übergebenen Argumente müssen auch mit dem
constexpr
oder mit dem Schlüsselwort
const
deklariert werden. Andernfalls verhalten sich solche Funktionen wie normale Funktionen, dh, während der Kompilierung werden ihre Werte nicht im Voraus berechnet.
Variablen können auch mit dem
constexpr
. In diesem Fall müssen die Werte dieser Variablen zur Kompilierungszeit berechnet werden. Ist dies nicht möglich, wird eine Kompilierungsfehlermeldung angezeigt.
Es ist interessant festzustellen, dass später in C ++ 17 die
Konstrukte constexpr-if und
constexpr-lambda erschienen.
Tupel-Datenstrukturen
Wie die
pair
ist die
tuple
(Tupel) eine Sammlung von Werten verschiedener Typen einer festen Größe. Hier ist ein Beispiel:
auto user_info = std::make_tuple("M", "Chowdhury", 25);
Manchmal ist es bequemer,
std::array
anstelle einer
tuple
verwenden. Diese Datenstruktur ähnelt den einfachen Arrays, die in der C-Sprache verwendet werden und mit zusätzlichen Funktionen aus der C ++ - Standardbibliothek ausgestattet sind. Diese Datenstruktur wurde in C ++ 11 angezeigt.
Automatischer Rückschluss auf den Argumenttyp der Klassenvorlage
Der Name dieser Funktion sieht ziemlich lang und komplex aus, aber tatsächlich gibt es hier nichts Kompliziertes. Die Hauptidee hierbei ist, dass in C ++ 17 Typargumentargumente auch für Standardklassenvorlagen ausgegeben werden. Bisher wurde dies nur für Funktionsvorlagen unterstützt. Als Ergebnis stellt sich heraus, dass sie früher so geschrieben haben:
std::pair<std::string, int> user = {"M", 25};
Mit der Veröffentlichung von C ++ 17 kann diese Konstruktion nun durch folgende ersetzt werden:
std::pair user = {"M", 25};
Die Typinferenz erfolgt implizit. Dieser Mechanismus ist noch praktischer, wenn es um Tupel geht. Nämlich bevor ich folgendes schreiben musste:
std::tuple<std::string, std::string, int> user ("M", "Chy", 25);
Jetzt sieht das gleiche so aus:
std::tuple user2("M", "Chy", 25);
Es ist erwähnenswert, dass diese Funktionen für diejenigen, die mit C ++ - Vorlagen nicht besonders vertraut sind, nicht besonders hervorzuheben sind.
Intelligente Zeiger
Das Arbeiten mit Zeigern in C ++ kann ein wahrer Albtraum sein. Dank der Freiheit, die die Sprache dem Programmierer gibt, ist es für ihn manchmal sehr schwierig, "sich nicht in den Fuß zu schießen". In vielen Fällen drängen Zeiger auf einen solchen „Schuss“ des Programmierers.
Glücklicherweise hat C ++ 11 intelligente Zeiger eingeführt, die viel praktischer sind als normale Zeiger. Sie helfen dem Programmierer, Speicherlecks zu vermeiden, indem sie nach Möglichkeit Ressourcen freisetzen. Darüber hinaus bieten sie eine Sicherheitsgarantie für Ausnahmen.
Zusammenfassung
Hier ist ein gutes Repository, das unserer Meinung nach für diejenigen interessant sein wird, die den Innovationen von C ++ folgen. In dieser Sprache taucht ständig etwas Neues auf. Hier haben wir nur einige moderne Merkmale der Sprache angesprochen. In der Tat gibt es viele von ihnen. Es ist möglich, dass wir noch über sie sprechen.
Liebe Leser! Welche modernen C ++ - Funktionen finden Sie am interessantesten und nützlichsten?
