Könnten Sie ein Beispiel geben, wo static_assert(...)
('C ++ 11') das Problem elegant lösen würde?
Ich bin mit der Laufzeit vertraut assert(...)
. Wann sollte ich es vorziehen, static_assert(...)
regelmäßig zu sein assert(...)
?
Auch boost
da BOOST_STATIC_ASSERT
drin heißt etwas , ist es dasselbe wie static_assert(...)
?
Antworten:
Aus dem Kopf ...
Angenommen, dies
SomeLibrary::Version
wird als statische Konstante deklariert und nicht als#define
d (wie in einer C ++ - Bibliothek zu erwarten).Im Gegensatz dazu müssen Sie
SomeLibrary
Ihren Code tatsächlich kompilieren , alles verknüpfen und die ausführbare Datei erst dann ausführen, um herauszufinden, dass Sie 30 Minuten damit verbracht haben, eine inkompatible Version von zu kompilierenSomeLibrary
.@Arak, als Antwort auf Ihren Kommentar: Ja, Sie können
static_assert
einfach überall sitzen, wie es aussieht:quelle
static_assert
einen Kontext ohne Ausführung festlegen? Es scheint ein sehr schönes Beispiel zu sein :)static_assert
. Wenn der Zustand erst bekannt wird, wenn das Programm ausgeführt wird, verwenden Sieassert
.Statische Zusicherung wird verwendet, um Zusicherungen zur Kompilierungszeit zu machen. Wenn die statische Zusicherung fehlschlägt, wird das Programm einfach nicht kompiliert. Dies ist in verschiedenen Situationen nützlich, z. B. wenn Sie einige Funktionen per Code implementieren, die entscheidend davon abhängen, ob das
unsigned int
Objekt genau 32 Bit hat. Sie können eine statische Zusicherung wie folgt setzenin Ihrem Code. Auf einer anderen Plattform mit unterschiedlich großem
unsigned int
Typ schlägt die Kompilierung fehl, wodurch der Entwickler auf den problematischen Teil des Codes aufmerksam gemacht und ihm empfohlen wird, ihn erneut zu implementieren oder zu überprüfen.In einem anderen Beispiel möchten Sie möglicherweise einen ganzzahligen Wert als
void *
Zeiger auf eine Funktion übergeben (ein Hack, der jedoch manchmal nützlich ist), und Sie möchten sicherstellen, dass der ganzzahlige Wert in den Zeiger passtMöglicherweise möchten Sie festlegen, dass dieser
char
Typ signiert istoder diese integrale Division mit negativen Werten rundet gegen Null
Und so weiter.
Laufzeit-Zusicherungen können in vielen Fällen anstelle von statischen Zusicherungen verwendet werden. Laufzeit-Zusicherungen funktionieren jedoch nur zur Laufzeit und nur dann, wenn die Kontrolle über die Zusicherung übergeht. Aus diesem Grund kann eine fehlerhafte Laufzeitzusicherung für längere Zeit unentdeckt ruhen.
Natürlich muss der Ausdruck in der statischen Zusicherung eine Konstante zur Kompilierungszeit sein. Es kann kein Laufzeitwert sein. Für Laufzeitwerte haben Sie keine andere Wahl, als das Gewöhnliche zu verwenden
assert
.quelle
static_assert
speziell auf C ++ 11 zu verweisen . Meinstatic_assert
obiges ist nur eine abstrakte Implementierung der statischen Behauptung. (Ich persönlich verwende so etwas im C-Code). Meine Antwort soll sich auf den allgemeinen Zweck statischer Zusicherungen und deren Unterschied zu Laufzeit-Zusicherungen beziehen.unsigned int
. Dies wird vom Standard nicht garantiert. Eine Variable vom Typunsigned int
könnte legal 32 Bit Speicher belegen und 16 davon unbenutzt lassen (und somit wäre das MakroUINT_MAX
gleich65535
). Die Art und Weise, wie Sie die erste statische Behauptung beschreiben ("unsigned int
Objekt mit genau 32 Bit"), ist irreführend. Um Ihrer Beschreibung zu entsprechen, sollte diese Behauptung ebenfalls enthalten sein :static_assert(UINT_MAX >= 0xFFFFFFFFu)
.Ich verwende es, um sicherzustellen, dass meine Annahmen über das Compilerverhalten, Header, Bibliotheken und sogar meinen eigenen Code korrekt sind. Zum Beispiel überprüfe ich hier, ob die Struktur korrekt auf die erwartete Größe gepackt wurde.
In einer Klasse Verpackung
stdio.h
istfseek()
, habe ich einige Verknüpfungen mit genommenenum Origin
und prüfen, ob diese Verknüpfungen mit den Konstanten ausrichten , definiert durchstdio.h
Sie sollen lieber
static_assert
über ,assert
wenn das Verhalten bei der Kompilierung definiert und zur Laufzeit nicht, wie die Beispiele , die ich oben gegeben habe. Ein Beispiel, in dem dies nicht der Fall ist, wäre die Überprüfung von Parametern und Rückkehrcodes.BOOST_STATIC_ASSERT
ist ein Pre-C ++ 0x-Makro, das unzulässigen Code generiert, wenn die Bedingung nicht erfüllt ist. Die Absichten sind dieselben, obwohl siestatic_assert
standardisiert sind und möglicherweise eine bessere Compilerdiagnose bieten.quelle
BOOST_STATIC_ASSERT
ist ein plattformübergreifender Wrapper fürstatic_assert
Funktionalität.Derzeit verwende ich static_assert, um "Konzepte" für eine Klasse zu erzwingen.
Beispiel:
Dies führt zu einem Fehler bei der Kompilierung, wenn eine der oben genannten Bedingungen nicht erfüllt ist.
quelle
Eine Möglichkeit besteht
static_assert
darin, sicherzustellen, dass eine Struktur (dh eine Schnittstelle zur Außenwelt, z. B. ein Netzwerk oder eine Datei) genau die Größe hat, die Sie erwarten. Dies würde Fälle erfassen, in denen jemand ein Mitglied aus der Struktur hinzufügt oder ändert, ohne die Konsequenzen zu erkennen. Dasstatic_assert
würde es abholen und den Benutzer alarmieren.quelle
In Ermangelung von Konzepten kann eine
static_assert
einfache und lesbare Typprüfung zur Kompilierungszeit verwendet werden, beispielsweise in Vorlagen:quelle
Dies beantwortet die ursprüngliche Frage nicht direkt, macht jedoch eine interessante Studie darüber, wie diese Überprüfungen der Kompilierungszeit vor C ++ 11 erzwungen werden können.
Kapitel 2 (Abschnitt 2.1) des modernen C ++ - Designs von Andrei Alexanderscu implementiert diese Idee solcher Behauptungen zur Kompilierungszeit
Vergleichen Sie das Makro STATIC_CHECK () und static_assert ()
quelle
Mit
static_assert
kann die Verwendung desdelete
Schlüsselworts folgendermaßen verboten werden:#define delete static_assert(0, "The keyword \"delete\" is forbidden.");
Jeder moderne C ++ - Entwickler möchte dies möglicherweise tun, wenn er oder sie einen konservativen Garbage Collector verwenden möchte, indem er nur Klassen und Strukturen verwendet , die den Operator new überladen , um eine Funktion aufzurufen, die Speicher auf dem konservativen Heap des konservativen Garbage Collector zuweist kann initialisiert und instanziiert werden, indem eine Funktion aufgerufen wird, die dies am Anfang der
main
Funktion tut .Zum Beispiel
main
schreibt jeder moderne C ++ - Entwickler, der den konservativen Garbage Collector Boehm-Demers-Weiser verwenden möchte, zu Beginn der Funktion:GC_init();
Und in jeder
class
undstruct
Überlastung aufoperator new
diese Weise:Und jetzt, da das
operator delete
nicht mehr benötigt wird, weil der konservative Garbage Collector von Boehm-Demers-Weiser dafür verantwortlich ist, jeden Speicherblock freizugeben und freizugeben, wenn er nicht mehr benötigt wird, möchte der Entwickler dasdelete
Schlüsselwort verbieten .Ein Weg ist das Überladen auf folgende
delete operator
Weise:Dies wird jedoch nicht empfohlen, da der moderne C ++ - Entwickler weiß, dass er fälschlicherweise die
delete operator
On- Runtime aufgerufen hat. Dies ist jedoch besser, wenn Sie dies bald bei der Kompilierung wissen.Die beste Lösung für dieses Szenario ist meiner Meinung nach die Verwendung der
static_assert
am Anfang dieser Antwort gezeigten.Natürlich kann das auch damit gemacht werden
BOOST_STATIC_ASSERT
, aber ich denke dasstatic_assert
ist besser und sollte immer mehr bevorzugt werden.quelle