Czy mógłbyś podać przykład, w którym static_assert(...)
('C ++ 11') elegancko rozwiązałoby problem?
Znam się na czasie wykonywania assert(...)
. Kiedy powinienem preferować static_assert(...)
zamiast zwykłego assert(...)
?
Poza boost
tym jest coś BOOST_STATIC_ASSERT
, co się nazywa , czy to jest to samo co static_assert(...)
?
Odpowiedzi:
Z czubka mojej głowy ...
Zakładając, że
SomeLibrary::Version
jest zadeklarowana jako stała statyczna, a nie#define
d (jak można by oczekiwać w bibliotece C ++).Porównajmy to z koniecznością rzeczywistego skompilowania
SomeLibrary
i skompilowania kodu, połączenia wszystkiego i uruchomienia pliku wykonywalnego tylko wtedy, aby dowiedzieć się, że spędziłeś 30 minut na kompilowaniu niezgodnej wersjiSomeLibrary
.@Arak, w odpowiedzi na twój komentarz: tak, możesz po
static_assert
prostu siedzieć gdziekolwiek, z wyglądu:źródło
static_assert
w kontekście braku wykonania? Wydaje się, że to bardzo fajny przykład :)static_assert
. Jeśli warunek nie będzie znany do czasu uruchomienia programu, użyjassert
.Asercja statyczna służy do tworzenia asercji w czasie kompilacji. Gdy asercja statyczna nie powiedzie się, program po prostu się nie kompiluje. Jest to przydatne w różnych sytuacjach, na przykład jeśli zaimplementujesz jakąś funkcjonalność za pomocą kodu, który w znacznym stopniu zależy od
unsigned int
obiektu mającego dokładnie 32 bity. Możesz umieścić takie statyczne potwierdzeniew swoim kodzie. Na innej platformie, z innym
unsigned int
typem kompilacji, kompilacja zakończy się niepowodzeniem, co zwróci uwagę programisty na problematyczną część kodu i doradzi mu ponowne zaimplementowanie lub ponowne sprawdzenie.Na przykład, możesz chcieć przekazać jakąś wartość całkowitą jako
void *
wskaźnik do funkcji (hack, ale czasami przydatny) i chcesz się upewnić, że wartość całkowita będzie pasować do wskaźnikaMożesz chcieć, aby zasób tego
char
typu był podpisanylub ten całkowy podział z wartościami ujemnymi zaokrągla się do zera
I tak dalej.
W wielu przypadkach potwierdzenia w czasie wykonywania mogą być używane zamiast potwierdzeń statycznych, ale asercje w czasie wykonywania działają tylko w czasie wykonywania i tylko wtedy, gdy kontrola przechodzi przez potwierdzenie. Z tego powodu niepomyślna asercja w czasie wykonywania może pozostawać uśpiona i niewykryta przez dłuższy czas.
Oczywiście wyrażenie w asercji statycznej musi być stałą czasu kompilacji. Nie może to być wartość czasu wykonywania. W przypadku wartości czasu wykonywania nie masz innego wyjścia, jak tylko użyć zwykłego
assert
.źródło
static_assert
konkretnie z C ++ 11. Mojastatic_assert
powyżej to tylko niektóre streszczenie realizacja twierdzenie statycznej. (Osobiście używam czegoś takiego w kodzie C). Moja odpowiedź ma dotyczyć ogólnego celu asercji statycznych i ich różnicy w stosunku do asercji w czasie wykonywania.unsigned int
. Nie jest to gwarantowane przez standard. Zmienna typuunsigned int
mogłaby legalnie zajmować 32 bity pamięci, pozostawiając 16 z nich nieużywanych (a zatem makroUINT_MAX
byłoby równe65535
). Zatem sposób, w jaki opisujesz pierwsze stwierdzenie statyczne („unsigned int
obiekt mający dokładnie 32 bity”) jest mylący. Pasujące do Twojego opisu, to stwierdzenie powinno być również uwzględnione:static_assert(UINT_MAX >= 0xFFFFFFFFu)
.Używam go, aby upewnić się, że moje założenia dotyczące zachowania kompilatora, nagłówków, bibliotek, a nawet mojego własnego kodu są poprawne. Na przykład tutaj sprawdzam, czy struktura została poprawnie zapakowana do oczekiwanego rozmiaru.
W opakowaniu klasy
stdio.h
„sfseek()
, mam podjąć jakieś skróty zenum Origin
i sprawdzić, czy te skróty wyrównać ze stałych zdefiniowanych przezstdio.h
Należy wolisz
static_assert
ponadassert
gdy zachowanie jest określona w czasie kompilacji, a nie w czasie wykonywania, takie jak przykładów mam podanych powyżej. Przykład, w którym tak nie jest , obejmowałby sprawdzanie parametrów i kodu powrotu.BOOST_STATIC_ASSERT
jest makrem sprzed C ++ 0x, które generuje niedozwolony kod, jeśli warunek nie jest spełniony. Zamierzenia są takie same, aczkolwiekstatic_assert
jest on ustandaryzowany i może zapewnić lepszą diagnostykę kompilatora.źródło
BOOST_STATIC_ASSERT
jest aplikacją typu wrapper dla platformystatic_assert
funkcjonalności.Obecnie używam static_assert w celu wymuszenia „Pojęcia” na klasie.
przykład:
Spowoduje to błąd czasu kompilacji, jeśli którykolwiek z powyższych warunków nie zostanie spełniony.
źródło
Jednym z zastosowań
static_assert
może być upewnienie się, że struktura (czyli interfejs ze światem zewnętrznym, takim jak sieć lub plik) ma dokładnie taki rozmiar, jakiego oczekujesz. To wychwyciłoby przypadki, w których ktoś dodaje lub modyfikuje element ze struktury bez zdawania sobie sprawy z konsekwencji.static_assert
By go podnieść i ostrzega użytkownika.źródło
W przypadku braku koncepcji można użyć
static_assert
do prostego i czytelnego sprawdzania typów w czasie kompilacji, na przykład w szablonach:źródło
Nie stanowi to bezpośredniej odpowiedzi na pierwotne pytanie, ale stanowi interesujące badanie, w jaki sposób wymusić te kontrole czasu kompilacji przed C ++ 11.
Rozdział 2 (sekcja 2.1) Modern C ++ Design autorstwa Andrei Alexanderscu implementuje taką ideę asercji w czasie kompilacji, jak ta
Porównaj makro STATIC_CHECK () i static_assert ()
źródło
static_assert
Mogą być wykorzystane do zabrania używaniadelete
słów kluczowych w ten sposób:#define delete static_assert(0, "The keyword \"delete\" is forbidden.");
Każdy współczesny programista C ++ może chcieć to zrobić, jeśli chce użyć konserwatywnego modułu odśmiecania pamięci, używając tylko klas es i struktur, które przeciążają operator new, aby wywołać funkcję, która przydziela pamięć na konserwatywnym stercie konserwatywnego modułu odśmiecania pamięci, który można zainicjować i utworzyć instancję, wywołując jakąś funkcję, która robi to na początku
main
funkcji.Na przykład każdy współczesny programista C ++, który chce użyć konserwatywnego garbage collectora Boehm-Demersa-Weisera, na początku
main
funkcji napisze:GC_init();
I w każdym
class
istruct
przeciążaj woperator new
ten sposób:A teraz, gdy
operator delete
nie jest już potrzebny, ponieważ konserwatywny moduł odśmiecania Boehm-Demers-Weiser jest odpowiedzialny zarówno za zwalnianie, jak i zwalnianie każdego bloku pamięci, gdy nie jest już potrzebny, programista chce zabronićdelete
słowa kluczowego.Jednym ze sposobów jest przeciążenie w
delete operator
ten sposób:Nie jest to jednak zalecane, ponieważ współczesny programista C ++ będzie wiedział, że omyłkowo wywołał plik
delete operator
czas wykonywania, ale lepiej to wiedzieć wkrótce w czasie kompilacji.Więc moim zdaniem najlepszym rozwiązaniem tego scenariusza jest użycie
static_assert
co pokazano na początku tej odpowiedzi.Oczywiście można to również zrobić
BOOST_STATIC_ASSERT
, ale myślę, żestatic_assert
jest to lepsze i zawsze powinno być preferowane.źródło