2013-08-13 4 views
30

Wiem, że static_assert sprawia, że ​​asercje w czasie kompilacji i assert - w czasie wykonywania, ale jaka jest różnica w praktyce? O ile mi zrozumieć, w głębi duszy są kawałki kodu, jakJaka jest różnica między asersem i static_assert?

if (condition == false) exit(); 
  • Czy ktoś może dać mi przykład gdzie tylkostatic_assert zadziała lub tylkoassert?
  • Czy robią coś, czego nie można w prosty sposób wyciągnąć z oświadczenia if?
  • Czy to jest zła praktyka, aby z nich korzystać?
+0

'static_assert' to deklaracja wbudowana w rdzeń. Nie rozszerza się do niczego, ponieważ jeśli nie powiedzie się, kompilacja ustaje. – jrok

+4

@KerrekSB Zapytałem ** trzy ** jasne pytania, proszę poświęć trochę czasu, aby je przeczytać przed przyjęciem założenia. – Oleksiy

+1

Używasz asert, aby określić, że jest błąd w logice programowania i że powinien on zostać naprawiony w kodzie. 'if' jest używane do rozgałęzienia między różnymi ścieżkami logicznymi w kodzie. Jest to duża różnica, aby – Default

Odpowiedz

35

Zadajesz trzy pytania, więc postaram się odpowiedzieć na każde z nich.

  • Czy ktoś może dać mi przykład gdzie tylkostatic_assert będzie działać, lub tylkoassert?

static_assert jest dobry do testowania logiki w kodzie w czasie kompilacji. assert jest dobry do sprawdzania przypadku w czasie wykonywania, który powinien zawsze mieć jeden wynik, ale może w jakiś sposób może spowodować nieoczekiwany wynik w nieprzewidzianych okolicznościach.Na przykład powinieneś używać tylko assert do określenia, czy wskaźnik przekazany do metody to null, gdy wydaje się, że nigdy nie powinno się zdarzyć. static_assert nie złapią tego.

  • Czy robią coś, czego proste oświadczenie if nie może zrobić?

assert mogą być wykorzystane do złamania wykonanie programu, więc można używać if, odpowiedni komunikat o błędzie, a następnie zatrzymać wykonywanie programu, aby uzyskać podobny efekt, ale assert jest nieco prostsze dla tej sprawy. static_assert jest oczywiście ważny tylko do wykrywania problemów z kompilacją, podczas gdy if musi być programowo poprawny i nie może ocenić tych samych oczekiwań podczas kompilacji. (Można jednak użyć if do wypowiedzenia komunikatu o błędzie w czasie wykonywania).

  • Czy to jest zła praktyka, aby z nich korzystać?

Wcale nie!

+0

Dobra odpowiedź jednak, dodając, że assert (wariant wykonawczy) działa tylko w kompilacjach debugujących i jest wydaniem noop w wersji prawdopodobnie jest dobrym pomysłem. Które mogą być dobre, w porównaniu z instrukcją if, z obszernymi testami debugowania, aby usunąć niektóre z możliwych zbędnych sprawdzeń błędów optymalizujących pod kątem wersji wydania. Również ostrzeżenie, aby nie umieszczać logiki zmiany stanu w nawiasie assert, ponieważ wynikowa logika nie będzie istnieć w kompilacjach wydań ... w związku z tym na przykład z assert (x ++ <12), x ++ nie będzie istnieć w kompilacjach wydań, tylko w debugowaniu. – Kit10

1

static_assert to dyrektywa kompilująca. Pozwala na sprawdzenie informacji o typie w czasie kompilacji. Spowoduje to awarię kompilacji i wygeneruje komunikat o błędzie, który w większości IDE zostanie przechwycony i wyświetlony w oknie błędu IDE.

static_assert(sizeof(int) == 4,"int should be 4 bytes"); 

assert jest dla środowiska wykonawczego, można sprawdzić wartość zmiennej. Jeśli asercja nie powiedzie się, wywoła to asercja. Będzie to powodować wiadomość okno o błędzie, który pojawi się na starcie w niektórych systemach operacyjnych (dochodzić realizacji zależny)

assert(("mypointer should never be null!", mypointer != nullptr)); 
+1

"dyrektywa" kompilatora prawdopodobnie nie jest terminologią, której bym użył ... –

+0

Makro assert zdefiniowane w '' nie przyjmuje dwóch argumentów – Joe

+0

@joe, prawe, poprawiono składnię. –

11

static_assert ma zrobić kompilację niepowodzeniem z określonym komunikatem, podczas gdy tradycyjny assert ma zakończyć wykonanie twojego programu.

6

OK, będę gryźć:

  • static_assert prace tylko jeśli chcesz kompilację bezskutecznie zatrzymać jeśli stan statyczny jest łamane: static_assert(sizeof(void*) != 3, "Wrong machine word size"); * Tylko dynamiczne twierdzenia można złapać dynamiczne warunki: assert(argc == 1);

  • Proste oświadczenia if muszą być prawidłowe i możliwe do skompilowania; Asercje statyczne powodują awarie kompilacji.

  • nr

*) Praktycznym przykładem może być zapobieganie nadużywaniu leków generycznych konstrukcji szablonów, takich jak int x; std::move<int&&>(x).

3

Czy to jest zła praktyka, aby z nich korzystać?

Jeśli nadużyto, tak, szczególnie assert.

Jeden nadużycie zależy od tych oświadczeń assert, aby być aktywnym. Nigdy nie powinieneś polegać na assert, aby cokolwiek zrobić, ponieważ kod można skompilować z NDEBUG zdefiniowanym, a następnie assert nic nie robi. Kod produkcyjny jest często kompilowany z NDEBUG zdefiniowany w celu zapewnienia, że ​​te instrukcje assert znikną.

O ile nie piszesz jednorazowego programu, który nie będzie trwał dłużej niż dzień lub dwa, nie powinieneś używać do sprawdzania danych wprowadzanych przez użytkownika. Użytkownicy nie dbają o to, gdzie kod się nie powiódł, a wydrukowany komunikat wygląda jak język obcy dla wielu użytkowników. Nie informuje użytkownika, jak naprawić błąd. Z założenia jest również bardzo pamiętliwy. Komunikat wygenerowany w odpowiedzi na błąd wprowadzany przez użytkownika powinien być komunikatem informującym użytkownika, jak rozwiązać problem. Najlepszą akcją po wiadomości jest zaoferowanie użytkownikowi sposobu na naprawienie błędu. Jeśli nie można tego zrobić, a jedyną możliwą odpowiedzią jest zakończenie programu, program powinien zakończyć się w sposób czysty. Zgodnie z projektem, assert nie powoduje całkowitego wyłączenia. Wzywa on abort() zamiast exit().

Jedną z konsekwencji abort() na wielu komputerach jest generowanie zrzutu pamięci. Zrzut główny jest świetnym komunikatem o błędzie dla programisty. Z zrzutem rdzenia programista może użyć debuggera, aby zobaczyć, co poszło nie tak z dużą szczegółowością. Minusem abort() jest to, że rzeczy nie są sprzątane. Przerwij "kończy program bez wykonywania destruktorów dla obiektów o automatycznym lub statycznym czasie przechowywania i bez wywoływania funkcji przekazanych do atexit()." Podsumowując: Używanie assert jest w porządku (i dobrze) do testowania błędów programistycznych, ale tylko w ustawieniach nieprodukcyjnych. Użyj czegoś innego, aby przetestować błędy użytkowników.