[dcl.attr.noreturn] bietet das folgende Beispiel:
[[ noreturn ]] void f() {
throw "error";
// OK
}
aber ich verstehe nicht, worum es geht [[noreturn]]
, weil der Rückgabetyp der Funktion bereits ist void
.
Was ist der Sinn des noreturn
Attributs? Wie soll es verwendet werden?
c++
c++11
attributes
noreturn
BЈовић
quelle
quelle
Antworten:
Das noreturn-Attribut soll für Funktionen verwendet werden, die nicht zum Aufrufer zurückkehren. Das bedeutet nicht, dass Funktionen ungültig sind (die zum Aufrufer zurückkehren - sie geben nur keinen Wert zurück), sondern Funktionen, bei denen der Kontrollfluss nach Beendigung der Funktion nicht zur aufrufenden Funktion zurückkehrt (z. B. Funktionen, die die Anwendung beenden, Schleife für immer oder Ausnahmen auslösen wie in Ihrem Beispiel).
Dies kann von Compilern verwendet werden, um einige Optimierungen vorzunehmen und bessere Warnungen zu generieren. Wenn beispielsweise
f
das Attribut noreturn vorhanden ist, kann der Compiler Sieg()
beim Schreiben davor warnen, dass der Code tot istf(); g();
. Ebenso kann der Compiler Sie nicht vor fehlenden return-Anweisungen nach Aufrufen von warnenf()
.quelle
execve
, die nicht zurückkehren sollte, aber könnte ? Sollte es das noreturn- Attribut haben?noreturn
Attribut nicht haben .noreturn
darf nur verwendet werden, wenn Ihre Funktion garantiert etwas tut, das das Programm beendet, bevor der Kontrollfluss zum Aufrufer zurückkehren kann - zum Beispiel, weil Sie exit (), abort (), assert (0) usw.noreturn
. Die Behandlung dieser Ausnahme ist nicht die gleiche wie die zurückgegebene. Code innerhalb destry
nach dem Aufruf ist immer noch nicht erreichbar, und wenn nicht, erfolgtvoid
keine Zuweisung oder Verwendung des Rückgabewerts.noreturn
teilt dem Compiler nicht mit, dass die Funktion keinen Wert zurückgibt. Es teilt dem Compiler mit, dass der Kontrollfluss nicht zum Aufrufer zurückkehrt . Dies ermöglicht es dem Compiler, eine Vielzahl von Optimierungen vorzunehmen - er muss keinen flüchtigen Zustand um den Aufruf herum speichern und wiederherstellen, er kann jeglichen Code, der sonst dem Aufruf folgen würde, durch Deadcode eliminieren usw.quelle
Dies bedeutet, dass die Funktion nicht abgeschlossen wird. Der Kontrollfluss wird die Anweisung nach dem Aufruf von
f()
:Die Informationen können vom Compiler / Optimierer auf verschiedene Arten verwendet werden. Der Compiler kann eine Warnung hinzufügen, dass der obige Code nicht erreichbar ist, und er kann den tatsächlichen Code
g()
auf verschiedene Arten ändern, um beispielsweise Fortsetzungen zu unterstützen.quelle
-Wno-return
und Sie erhalten eine Warnung. Wahrscheinlich nicht die, die Sie erwartet haben, aber es reicht wahrscheinlich aus, Ihnen mitzuteilen, dass der Compiler[[noreturn]]
weiß, was ist, und dass er es nutzen kann. (Ich bin ein bisschen überrascht, dass-Wunreachable-code
nicht-Wmissing-noreturn
, die Warnung impliziert, dass die Flussanalyse festgestellt hat, dass derstd::cout
nicht erreichbar ist. Ich habe nicht genug GCC zur Hand, um mir die generierte Baugruppe anzusehen, aber ich wäre nicht überrascht, wenn der Anruf beioperator<<
-O1
es bereits aus , diesen nicht erreichbaren Code ohne den[[noreturn]]
Hinweis zu löschen.[[noreturn]]
den Code daraus ableiten kann. Wenn diese Übersetzungseinheit nur eine Deklaration der Funktion hätte, die an einer anderen Stelle definiert wurde, könnte der Compiler diesen Code nicht löschen , da er nicht weiß, dass die Funktion nicht zurückgibt. Hier sollte das Attribut dem Compiler helfen.Frühere Antworten haben richtig erklärt, was Noreturn ist, aber nicht, warum es existiert. Ich denke nicht, dass die "Optimierungs" -Kommentare der Hauptzweck sind: Funktionen, die nicht zurückkehren, sind selten und müssen normalerweise nicht optimiert werden. Ich denke eher, dass die Hauptaufgabe von noreturn darin besteht, falsch positive Warnungen zu vermeiden. Betrachten Sie beispielsweise diesen Code:
Wäre abort () nicht als "noreturn" markiert worden, hätte der Compiler möglicherweise davor gewarnt, dass dieser Code einen Pfad hat, in dem f nicht wie erwartet eine Ganzzahl zurückgibt. Da abort () als no return markiert ist, weiß es, dass der Code korrekt ist.
quelle
Typ theoretisch gesprochen,
void
heißt das in anderen Sprachenunit
odertop
. Sein logisches Äquivalent ist Wahr . Jeder Wert kann legitimiert umgewandelt werdenvoid
(jeder Typ ist ein Subtyp vonvoid
). Betrachten Sie es als "Universum" -Set; Es gibt keine gemeinsamen Operationen für alle Werte auf der Welt, daher gibt es keine gültigen Operationen für einen Wert vom Typvoid
. Anders ausgedrückt: Wenn Sie sagen, dass etwas zum Universum gehört, erhalten Sie keinerlei Informationen - Sie wissen es bereits. Das Folgende ist also Ton:Die folgende Zuordnung lautet jedoch nicht:
[[noreturn]]
, Auf der anderen Seite, manchmal genannt wirdempty
,Nothing
,Bottom
oderBot
und ist die logische Äquivalent Falsch . Es hat überhaupt keine Werte, und ein Ausdruck dieses Typs kann in einen beliebigen Typ umgewandelt werden (dh ist ein Subtyp eines beliebigen Typs). Dies ist die leere Menge. Beachten Sie, dass jemand, der Ihnen sagt, dass "der Wert des Ausdrucks foo () zur leeren Menge gehört", sehr informativ ist - er sagt Ihnen, dass dieser Ausdruck niemals seine normale Ausführung abschließen wird. es wird abbrechen, werfen oder hängen. Es ist das genaue Gegenteil vonvoid
.Das Folgende macht also keinen Sinn (Pseudo-C ++, da
noreturn
es sich nicht um einen erstklassigen C ++ - Typ handelt)Die folgende Zuordnung ist jedoch absolut legitim, da
throw
der Compiler versteht, dass er nicht zurückgibt:In einer perfekten Welt können Sie
noreturn
als Rückgabewert für dieraise()
obige Funktion Folgendes verwenden:Leider erlaubt C ++ dies nicht, wahrscheinlich aus praktischen Gründen. Stattdessen können Sie
[[ noreturn ]]
Attribute verwenden, mit denen Sie Compileroptimierungen und Warnungen steuern können.quelle
void
undvoid
niemals bewertet werdentrue
oderfalse
oder irgendetwas anderes.true
, meine ich nicht "den Werttrue
des Typsbool
", sondern den logischen Sinn, siehe Curry-Howard-Korrespondenz(void)true;
ist vollkommen gültig, wie die Antwort nahelegt.void(true)
ist syntaktisch etwas völlig anderes. Es ist ein Versuch, ein neues Objekt vom Typ zu erstellen,void
indem ein Konstruktor mittrue
als Argument aufgerufen wird. Dies scheitert unter anderem daran, dassvoid
es nicht erstklassig ist.