Keine C ++ Liebe, wenn es um die "versteckten Funktionen von" Fragen geht? Ich dachte, ich würde es da rauswerfen. Was sind einige der versteckten Funktionen von C ++?
c++
hidden-features
Craig H.
quelle
quelle
Antworten:
Die meisten C ++ - Programmierer kennen den ternären Operator:
Sie erkennen jedoch nicht, dass es als Wert verwendet werden kann:
Das ist eine Abkürzung für
Vorsichtig verwenden :-)
quelle
(value ? function1 : function2)()
.function1
undfunction2
implizit in Funktionszeiger konvertiert werden und das Ergebnis implizit zurückkonvertiert wird.Sie können URIs fehlerfrei in eine C ++ - Quelle einfügen. Beispielsweise:
quelle
goto
, die C ++ hat). Alles, was nach zwei Schrägstrichen folgt, ist ein Kommentar. Daher mithttp://stackoverflow.com
,http
ist ein Label (man könnte theoretisch schreibengoto http;
), und//stackoverflow.com
ist nur ein End-of-Line - Kommentar. Beide sind legales C ++, daher wird das Konstrukt kompiliert. Es macht natürlich nichts vage Nützliches.goto http;
Folgt leider nicht wirklich der URL. :(C ++ - Programmierer bevorzugen es, Zeiger zu vermeiden, da Fehler auftreten können.
Das coolste C ++, das ich je gesehen habe? Analoge Literale.
quelle
Ich stimme den meisten Posts dort zu: C ++ ist eine Multi-Paradigma-Sprache, daher sind die "versteckten" Funktionen, die Sie finden (außer "undefinierten Verhaltensweisen", die Sie unbedingt vermeiden sollten), eine clevere Verwendung von Einrichtungen.
Die meisten dieser Einrichtungen sind keine integrierten Funktionen der Sprache, sondern bibliotheksbasierte.
Das wichtigste ist das RAII , das von C ++ - Entwicklern aus der C-Welt oft jahrelang ignoriert wird. Das Überladen von Operatoren ist häufig eine missverstandene Funktion, die sowohl Array-ähnliches Verhalten (Indexoperator) als auch zeigerähnliche Operationen (intelligente Zeiger) und integrierte Operationen (Multiplikation von Matrizen) ermöglicht.
Die Verwendung von Ausnahmen ist oft schwierig, kann jedoch mit etwas Arbeit durch Ausnahmesicherheit wirklich robusten Code erzeugen (einschließlich Code, der nicht fehlschlägt oder über Commit-ähnliche Funktionen verfügt, die erfolgreich sind oder zu denen zurückgesetzt wird) seinen ursprünglichen Zustand).
Die bekannteste "versteckte" Funktion von C ++ ist die Vorlagen-Metaprogrammierung , da Sie Ihr Programm teilweise (oder vollständig) zur Kompilierungszeit anstatt zur Laufzeit ausführen lassen können. Dies ist jedoch schwierig, und Sie müssen die Vorlagen genau kennen, bevor Sie sie ausprobieren können.
Andere nutzen das multiple Paradigma, um "Programmierweisen" außerhalb des Vorfahren von C ++, dh C, zu erzeugen.
Durch die Verwendung von Funktoren können Sie Funktionen simulieren, mit der zusätzlichen Typensicherheit und dem Status. Mit dem Befehlsmuster können Sie die Codeausführung verzögern. Die meisten anderen Entwurfsmuster können einfach und effizient in C ++ implementiert werden, um alternative Codierungsstile zu erstellen, die nicht in der Liste der "offiziellen C ++ - Paradigmen" enthalten sein sollen.
Mithilfe von Vorlagen können Sie Code erstellen, der für die meisten Typen geeignet ist, auch nicht für den, an den Sie zuerst gedacht haben. Sie können auch die Typensicherheit erhöhen (wie bei einem automatisierten typsicheren Malloc / Realloc / Free). C ++ - Objektfunktionen sind sehr leistungsfähig (und daher gefährlich, wenn sie unachtsam verwendet werden), aber selbst der dynamische Polymorphismus hat seine statische Version in C ++: das CRTP .
Ich habe festgestellt, dass die meisten Bücher vom Typ " Effective C ++ " von Scott Meyers oder Bücher vom Typ " Exceptional C ++ " von Herb Sutter sowohl leicht zu lesen sind als auch eine Fülle von Informationen über bekannte und weniger bekannte Funktionen von C ++ enthalten.
Unter meinen bevorzugten ist eine, die die Haare eines jeden Java-Programmierers vor Entsetzen erheben sollte: In C ++ ist die objektorientierteste Möglichkeit, einem Objekt eine Funktion hinzuzufügen , die Funktion eines Nichtmitglieds anstelle eines Mitglieds. Funktion (dh Klassenmethode), weil:
In C ++ besteht die Schnittstelle einer Klasse sowohl aus ihren Member-Funktionen als auch aus den Nicht-Member-Funktionen im selben Namespace
Nicht-Freund-Nicht-Mitglied-Funktionen haben keinen privilegierten Zugriff auf die interne Klasse. Wenn Sie also eine Member-Funktion über eine Nicht-Member-Non-Friend-Funktion verwenden, wird die Kapselung der Klasse geschwächt.
Dies überrascht selbst erfahrene Entwickler immer wieder.
(Quelle: Unter anderem Herb Sutters Online-Guru der Woche Nr. 84: http://www.gotw.ca/gotw/084.htm )
quelle
Ein Sprachmerkmal, das ich für etwas versteckt halte, weil ich während meiner gesamten Schulzeit noch nie davon gehört hatte, ist der Namespace-Alias. Ich wurde erst darauf aufmerksam gemacht, als ich in der Boost-Dokumentation auf Beispiele dafür stieß. Jetzt, da ich davon weiß, können Sie es natürlich in jeder Standard-C ++ - Referenz finden.
quelle
using
.Im init-Teil einer
for
Schleife können nicht nur Variablen deklariert werden , sondern auch Klassen und Funktionen.Dies ermöglicht mehrere Variablen unterschiedlichen Typs.
quelle
Der Array-Operator ist assoziativ.
A [8] ist ein Synonym für * (A + 8). Da Addition assoziativ ist, kann dies als * (8 + A) umgeschrieben werden, was ein Synonym für ..... 8 [A] ist.
Du hast nicht nützlich gesagt ... :-)
quelle
A
überhaupt keine Rolle. Wenn zum BeispielA
ein sindchar*
, würde der Code immer noch gültig sein.Eine Sache, die wenig bekannt ist, ist, dass Gewerkschaften auch Vorlagen sein können:
Und sie können auch Konstruktoren und Elementfunktionen haben. Nur nichts, was mit Vererbung zu tun hat (einschließlich virtueller Funktionen).
quelle
From
undTo
entsprechend gesetzt und verwendet werden. Eine solche Vereinigung kann jedoch mit definiertem Verhalten verwendet werden (wobeiTo
es sich um ein Array von Zeichen ohne Vorzeichen oder eine Struktur handelt, mit der eine Anfangssequenz geteilt wirdFrom
). Selbst wenn Sie es undefiniert verwenden, kann es für Arbeiten auf niedriger Ebene nützlich sein. Auf jeden Fall ist dies nur ein Beispiel für eine Gewerkschaftsvorlage - es kann andere Verwendungszwecke für eine Vorlagenvereinigung geben.C ++ ist eine Multi-Paradigmen-Sprache. Sie können Ihr letztes Geld darauf setzen, dass es versteckte Funktionen gibt. Ein Beispiel von vielen: Template-Metaprogrammierung . Niemand im Normungsausschuss beabsichtigte, dass es eine Turing-vollständige Subsprache geben sollte, die zur Kompilierungszeit ausgeführt wird.
quelle
Eine weitere versteckte Funktion, die in C nicht funktioniert, ist die Funktionalität des unären
+
Operators. Sie können es verwenden, um alle möglichen Dinge zu fördern und zu verfallenKonvertieren einer Aufzählung in eine Ganzzahl
Und Ihr Enumeratorwert, der zuvor seinen Aufzählungstyp hatte, hat jetzt den perfekten Ganzzahltyp, der zu seinem Wert passt. Manuell würde man diesen Typ kaum kennen! Dies ist beispielsweise erforderlich, wenn Sie einen überladenen Operator für Ihre Aufzählung implementieren möchten.
Holen Sie sich den Wert aus einer Variablen
Sie müssen eine Klasse verwenden, die einen statischen Initialisierer innerhalb der Klasse ohne Definition außerhalb der Klasse verwendet, aber manchmal keine Verknüpfung herstellt. Der Operator kann dabei helfen, eine temporäre Datei zu erstellen, ohne Annahmen oder Abhängigkeiten von ihrem Typ zu treffen
Zerlegen Sie ein Array in einen Zeiger
Möchten Sie zwei Zeiger an eine Funktion übergeben, aber es funktioniert einfach nicht? Der Bediener kann helfen
quelle
Die Lebensdauer von Provisorien, die an konstante Referenzen gebunden sind, ist eine, die nur wenige Menschen kennen. Zumindest ist es mein Lieblingswissen in C ++, von dem die meisten Leute nichts wissen.
quelle
Eine nette Funktion, die nicht oft verwendet wird, ist der funktionsweite Try-Catch-Block:
Die Hauptverwendung wäre, eine Ausnahme in eine andere Ausnahmeklasse zu übersetzen und erneut zu werfen oder zwischen Ausnahmen und einer auf Rückgabe basierenden Fehlercodebehandlung zu übersetzen.
quelle
return
aus dem Catch-Block von Function Try nur erneut werfen können.Viele kennen die
identity
/id
metafunktion, aber es gibt einen guten Anwendungsfall für Fälle ohne Vorlage: Einfaches Schreiben von Erklärungen:Es hilft sehr, C ++ - Deklarationen zu entschlüsseln!
quelle
template<typename Ret,typename... Args> using function = Ret (Args...); template<typename T> using pointer = *T;
->pointer<function<void,int>> f(pointer<function<void,void>>);
oderpointer<void(int)> f(pointer<void()>);
oderfunction<pointer<function<void,int>>,pointer<function<void,void>>> f;
Eine ziemlich versteckte Funktion ist, dass Sie Variablen innerhalb einer if-Bedingung definieren können und ihr Bereich sich nur über die if- und else-Blöcke erstreckt:
Einige Makros verwenden dies, um beispielsweise einen "gesperrten" Bereich wie diesen bereitzustellen:
Auch BOOST_FOREACH benutzt es unter der Haube. Um dies zu vervollständigen, ist es nicht nur in einem if möglich, sondern auch in einem Switch:
und in einer while-Schleife:
(und auch in einem Zustand). Aber ich bin mir nicht sicher, ob das alles so nützlich ist :)
quelle
if((a = f()) == b) ...
, aber diese Antwort deklariert tatsächlich eine Variable in der Bedingung.for(...; int i = foo(); ) ...;
dies durch den Körper gehen, solangei
es wahr ist, und es jedes Mal neu initialisieren. Die Schleife, die Sie zeigen, demonstriert einfach eine Variablendeklaration, aber keine Variablendeklaration, die gleichzeitig als Bedingung fungiert :)Verhindern, dass Kommaoperatoren Operatorüberladungen aufrufen
Manchmal verwenden Sie den Kommaoperator gültig, möchten aber sicherstellen, dass kein benutzerdefinierter Kommaoperator in die Quere kommt, weil Sie sich beispielsweise auf Sequenzpunkte zwischen der linken und rechten Seite verlassen oder sicherstellen möchten, dass nichts den gewünschten stört Aktion. Hier
void()
kommt das Spiel ins Spiel:Ignoriere die Platzhalter, die ich für die Bedingung und den Code angegeben habe. Was wichtig ist
void()
, ist das , was den Compiler dazu zwingt, den eingebauten Kommaoperator zu verwenden. Dies kann manchmal auch bei der Implementierung von Merkmalsklassen hilfreich sein.quelle
Array-Initialisierung im Konstruktor. Zum Beispiel in einer Klasse, wenn wir ein Array von
int
as haben:Wir können alle Elemente im Array auf ihre Standardeinstellung (hier alle Elemente des Arrays auf Null) im Konstruktor wie folgt initialisieren:
quelle
Oooh, ich kann stattdessen eine Liste mit Tierhassen erstellen:
Auf der positiven Seite
quelle
Sie können ohne undefiniertes Verhalten und mit erwarteter Semantik auf geschützte Daten und Funktionsmitglieder jeder Klasse zugreifen. Lesen Sie weiter, um zu sehen, wie. Lesen Sie dazu auch den Fehlerbericht .
Normalerweise verbietet Ihnen C ++ den Zugriff auf nicht statisch geschützte Elemente des Objekts einer Klasse, selbst wenn diese Klasse Ihre Basisklasse ist
Das ist verboten: Sie und der Compiler wissen nicht, worauf die Referenz tatsächlich verweist. Es könnte sich um ein
C
Objekt handeln. In diesem FallB
hat die Klasse kein Geschäft und keine Ahnung von ihren Daten. Ein solcher Zugriff wird nur gewährt, wennx
auf eine abgeleitete oder von dieser abgeleitete Klasse verwiesen wird. Und es könnte jedem beliebigen Code erlauben, jedes geschützte Mitglied zu lesen, indem nur eine "Wegwerf" -Klasse gebildet wird, die Mitglieder vorliest, zum Beispielstd::stack
:Wie Sie sehen, würde dies sicherlich viel zu viel Schaden anrichten. Aber jetzt erlauben Mitgliedszeiger, diesen Schutz zu umgehen! Der entscheidende Punkt ist, dass der Typ eines Mitgliedszeigers an die Klasse gebunden ist, die das Mitglied tatsächlich enthält - nicht an die Klasse, die Sie bei der Übernahme der Adresse angegeben haben. Dies ermöglicht es uns, die Überprüfung zu umgehen
Und natürlich funktioniert es auch mit dem
std::stack
Beispiel.Mit einer using-Deklaration in der abgeleiteten Klasse, die den Mitgliedsnamen öffentlich macht und auf das Mitglied der Basisklasse verweist, wird dies noch einfacher.
quelle
Eine weitere versteckte Funktion ist, dass Sie Klassenobjekte aufrufen können, die in Funktionszeiger oder Referenzen konvertiert werden können. Die Überlastungsauflösung erfolgt anhand des Ergebnisses, und die Argumente werden perfekt weitergeleitet.
Diese werden als "Ersatzanruffunktionen" bezeichnet.
quelle
Versteckte Funktionen:
Wenn eine Funktion eine Ausnahme auslöst, die nicht in ihren Ausnahmespezifikationen aufgeführt ist, die Funktion jedoch
std::bad_exception
in ihrer Ausnahmespezifikation enthält, wird die Ausnahme in konvertiertstd::bad_exception
und automatisch ausgelöst. Auf diese Weise wissen Sie zumindest, dass einbad_exception
geworfen wurde. Lesen Sie hier mehr .Funktionsversuchsblöcke
Das Template-Schlüsselwort zur Unterscheidung von Typedefs in einer Klassenvorlage. Wenn der Name eines Mitglied Template - Spezialisierung erscheint nach
.
,->
oder::
Operator, und dieser Name hat explizit qualifizierte Template - Parameter, Präfix das Element Template - Namen mit der Keyword - Vorlage. Lesen Sie hier mehr .Die Standardeinstellungen für Funktionsparameter können zur Laufzeit geändert werden. Lesen Sie hier mehr .
A[i]
funktioniert so gut wiei[A]
Temporäre Instanzen einer Klasse können geändert werden! Eine nicht konstante Mitgliedsfunktion kann für ein temporäres Objekt aufgerufen werden. Beispielsweise:
Lesen Sie hier mehr .
Wenn vor und nach dem Operatorausdruck
:
ternary (?:
) zwei verschiedene Typen vorhanden sind , ist der resultierende Typ des Ausdrucks der allgemeinste der beiden. Beispielsweise:quelle
map::operator[]
Erstellt einen Eintrag, wenn der Schlüssel fehlt, und gibt den Verweis auf den standardmäßig erstellten Eintragswert zurück. So können Sie schreiben:Ich bin erstaunt, wie viele C ++ - Programmierer das nicht wissen.
quelle
.find()
.const map::operator[]
generiert Fehlermeldungen"Durch das Einfügen von Funktionen oder Variablen in einen namenlosen Namespace wird die Verwendung von
static
eingeschränkt, um sie auf den Dateibereich zu beschränken.quelle
static
globale Geltungsbereich in keiner Weise veraltet. (Als Referenz: C ++ 03 §D.2)static
use sollte nur innerhalb eines Klassentyps oder einer Funktion verwendet werden.Das Definieren gewöhnlicher Freundfunktionen in Klassenvorlagen erfordert besondere Aufmerksamkeit:
In diesem Beispiel erstellen zwei verschiedene Instanziierungen zwei identische Definitionen - eine direkte Verletzung des ODR
Wir müssen daher sicherstellen, dass die Vorlagenparameter der Klassenvorlage im Typ einer in dieser Vorlage definierten Friend-Funktion angezeigt werden (es sei denn, wir möchten mehr als eine Instanziierung einer Klassenvorlage in einer bestimmten Datei verhindern, dies ist jedoch eher unwahrscheinlich). Wenden wir dies auf eine Variation unseres vorherigen Beispiels an:
Haftungsausschluss: Ich habe diesen Abschnitt aus C ++ - Vorlagen eingefügt : The Complete Guide / Section 8.4
quelle
void-Funktionen können void-Werte zurückgeben
Wenig bekannt, aber der folgende Code ist in Ordnung
Aswell wie der folgende seltsam aussehende
Wenn Sie dies wissen, können Sie in einigen Bereichen davon profitieren. Ein Beispiel:
void
Funktionen können keinen Wert zurückgeben, aber Sie können auch nicht einfach nichts zurückgeben, da sie möglicherweise mit nicht ungültig instanziiert werden. Anstatt den Wert in einer lokalen Variablen zu speichern, die einen Fehler verursachtvoid
, geben Sie einfach einen Wert direkt zurückquelle
Lesen Sie eine Datei in einen Vektor von Zeichenfolgen:
istream_iterator
quelle
vector<string> V((istream_iterator<string>(cin)), istream_iterator<string>());
- fehlende Klammern nach dem zweiten ParameterSie können Bitfelder vorlegen.
Ich habe mir noch keinen Zweck dafür ausgedacht, aber es hat mich verdammt noch mal überrascht.
quelle
Eine der interessantesten Grammatiken aller Programmiersprachen.
Drei dieser Dinge gehören zusammen und zwei sind etwas ganz anderes ...
Alle außer dem dritten und fünften definieren ein
SomeType
Objekt auf dem Stapel und initialisieren es (mitu
in den ersten beiden Fällen und dem Standardkonstruktor im vierten. Der dritte deklariert eine Funktion, die keine Parameter akzeptiert und a zurückgibtSomeType
. Der fünfte deklariert ähnlich eine Funktion , die einen Parameter mit Werten vom Typ nimmtSomeType
benanntu
.quelle
Vorwärtserklärungen loswerden:
Schreiben von switch-Anweisungen mit ?: Operatoren:
Alles in einer einzigen Zeile erledigen:
Nullstellen von Strukturen ohne Memset:
Winkel- und Zeitwerte normalisieren / umbrechen:
Verweisen von Referenzen:
quelle
FStruct s = {};
ist noch kürzer.main
? Ich würde vorschlagenglobal().main();
und einfach den Singleton vergessen ( Sie können einfach mit dem temporären arbeiten, wodurch die Lebensdauer verlängert wird )Der ternäre bedingte Operator
?:
verlangt, dass sein zweiter und dritter Operand "akzeptable" Typen haben (informell sprechen). Diese Anforderung hat jedoch eine Ausnahme (Wortspiel beabsichtigt): Entweder der zweite oder der dritte Operand kann ein Wurfausdruck sein (der Typ hatvoid
), unabhängig vom Typ des anderen Operanden.Mit anderen Worten, man kann die folgenden genau gültigen C ++ - Ausdrücke mit dem
?:
Operator schreibenÜbrigens ist die Tatsache, dass throw expression tatsächlich ein Ausdruck (vom Typ
void
) und keine Anweisung ist, ein weiteres wenig bekanntes Merkmal der C ++ - Sprache. Dies bedeutet unter anderem, dass der folgende Code vollkommen gültig istobwohl es nicht viel Sinn macht, es auf diese Weise zu tun (vielleicht ist dies in einem generischen Vorlagencode nützlich).
quelle
Die Dominanzregel ist nützlich, aber wenig bekannt. Selbst wenn sich die Mitglieder in einem nicht eindeutigen Pfad durch ein Gitter der Basisklasse befinden, ist die Namenssuche für ein teilweise verstecktes Mitglied eindeutig, wenn das Mitglied zu einer virtuellen Basisklasse gehört:
Ich habe dies verwendet, um eine Ausrichtungsunterstützung zu implementieren , die mithilfe der Dominanzregel automatisch die strengste Ausrichtung ermittelt.
Dies gilt nicht nur für virtuelle Funktionen, sondern auch für typedef Namen, statische / nicht virtuelle Mitglieder und alles andere. Ich habe gesehen, dass es verwendet wurde, um überschreibbare Merkmale in Metaprogrammen zu implementieren.
quelle
struct C
in Ihr Beispiel aufgenommen haben ...? Prost.