SafeInt — Klasa

Rozszerza liczby pierwotne liczb całkowitych, aby zapobiec przepełnieniu liczb całkowitych i umożliwia porównywanie różnych typów liczb całkowitych.

Uwaga

Najnowsza wersja biblioteki Sejf Int znajduje się w lokalizacji https://github.com/dcleblanc/SafeInt. Aby użyć biblioteki Sejf Int, sklonuj repozytorium i#include "SafeInt.hpp"

Składnia

template<typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY>
class SafeInt;

Parametry

T
Typ liczby całkowitej lub parametru logicznego, który SafeInt zastępuje.

E
Wyliczony typ danych, który definiuje zasady obsługi błędów.

U
Typ liczby całkowitej lub parametru logicznego pomocniczego operandu.

Rhs
[in] Parametr wejściowy reprezentujący wartość po prawej stronie operatora w kilku funkcjach autonomicznych.

i
[in] Parametr wejściowy reprezentujący wartość po prawej stronie operatora w kilku funkcjach autonomicznych.

Bitów
[in] Parametr wejściowy reprezentujący wartość po prawej stronie operatora w kilku funkcjach autonomicznych.

Członkowie

Konstruktory publiczne

Nazwa/nazwisko opis
SafeInt::SafeInt Konstruktor domyślny.

Operatory przypisania

Nazwisko Składnia
= template<typename U>
SafeInt<T,E>& operator= (const U& rhs)
= SafeInt<T,E>& operator= (const T& rhs) throw()
= template<typename U>
SafeInt<T,E>& operator= (const SafeInt<U, E>& rhs)
= SafeInt<T,E>& operator= (const SafeInt<T,E>& rhs) throw()

Operatory rzutowania

Nazwisko Składnia
bool operator bool() throw()
char operator char() const
znak ze znakiem operator signed char() const
unsigned char operator unsigned char() const
__int16 operator __int16() const
niepodpisane __int16 operator unsigned __int16() const
__int32 operator __int32() const
__int32 bez znaku operator unsigned __int32() const
długi operator long() const
unsigned long operator unsigned long() const
__int64 operator __int64() const
niepodpisane __int64 operator unsigned __int64() const
wchar_t operator wchar_t() const

Operatory porównania

Nazwisko Składnia
< template<typename U>

bool operator< (U rhs) const throw()
< bool operator< (SafeInt<T,E> rhs) const throw()
>= template<typename U>

bool operator>= (U rhs) const throw()
>= Bool operator>= (SafeInt<T,E> rhs) const throw()
> template<typename U>

bool operator> (U rhs) const throw()
> Bool operator> (SafeInt<T,E> rhs) const throw()
<= template<typename U>

bool operator<= (U rhs) const throw()
<= bool operator<= (SafeInt<T,E> rhs) const throw()
== template<typename U>

bool operator== (U rhs) const throw()
== bool operator== (bool rhs) const throw()
== bool operator== (SafeInt<T,E> rhs) const throw()
!= template<typename U>

bool operator!= (U rhs) const throw()
!= bool operator!= (bool b) const throw()
!= bool operator!= (SafeInt<T,E> rhs) const throw()

Operatory arytmetyczne

Nazwisko Składnia
+ const SafeInt<T,E>& operator+ () const throw()
- SafeInt<T,E> operator- () const
++ SafeInt<T,E>& operator++ ()
-- SafeInt<T,E>& operator-- ()
% template<typename U>

SafeInt<T,E> operator% (U rhs) const
% SafeInt<T,E> operator% (SafeInt<T,E> rhs) const
%= template<typename U>

SafeInt<T,E>& operator%= (U rhs)
%= template<typename U>

SafeInt<T,E>& operator%= (SafeInt<U, E> rhs)
* template<typename U>

SafeInt<T,E> operator* (U rhs) const
* SafeInt<T,E> operator* (SafeInt<T,E> rhs) const
*= SafeInt<T,E>& operator*= (SafeInt<T,E> rhs)
*= template<typename U>

SafeInt<T,E>& operator*= (U rhs)
*= template<typename U>

SafeInt<T,E>& operator*= (SafeInt<U, E> rhs)
/ template<typename U>

SafeInt<T,E> operator/ (U rhs) const
/ SafeInt<T,E> operator/ (SafeInt<T,E> rhs ) const
/= SafeInt<T,E>& operator/= (SafeInt<T,E> i)
/= template<typename U>

SafeInt<T,E>& operator/= (U i)
/= template<typename U>

SafeInt<T,E>& operator/= (SafeInt<U, E> i)
+ SafeInt<T,E> operator+ (SafeInt<T,E> rhs) const
+ template<typename U>

SafeInt<T,E> operator+ (U rhs) const
+= SafeInt<T,E>& operator+= (SafeInt<T,E> rhs)
+= template<typename U>

SafeInt<T,E>& operator+= (U rhs)
+= template<typename U>

SafeInt<T,E>& operator+= (SafeInt<U, E> rhs)
- template<typename U>

SafeInt<T,E> operator- (U rhs) const
- SafeInt<T,E> operator- (SafeInt<T,E> rhs) const
-= SafeInt<T,E>& operator-= (SafeInt<T,E> rhs)
-= template<typename U>

SafeInt<T,E>& operator-= (U rhs)
-= template<typename U>

SafeInt<T,E>& operator-= (SafeInt<U, E> rhs)

Operatory logiczne

Nazwisko Składnia
! bool operator !() const throw()
~ SafeInt<T,E> operator~ () const throw()
<< template<typename U>

SafeInt<T,E> operator<< (U bits) const throw()
<< template<typename U>

SafeInt<T,E> operator<< (SafeInt<U, E> bits) const throw()
<<= template<typename U>

SafeInt<T,E>& operator<<= (U bits) throw()
<<= template<typename U>

SafeInt<T,E>& operator<<= (SafeInt<U, E> bits) throw()
>> template<typename U>

SafeInt<T,E> operator>> (U bits) const throw()
>> template<typename U>

SafeInt<T,E> operator>> (SafeInt<U, E> bits) const throw()
>>= template<typename U>

SafeInt<T,E>& operator>>= (U bits) throw()
>>= template<typename U>

SafeInt<T,E>& operator>>= (SafeInt<U, E> bits) throw()
& SafeInt<T,E> operator& (SafeInt<T,E> rhs) const throw()
& template<typename U>

SafeInt<T,E> operator& (U rhs) const throw()
&= SafeInt<T,E>& operator&= (SafeInt<T,E> rhs) throw()
&= template<typename U>

SafeInt<T,E>& operator&= (U rhs) throw()
&= template<typename U>

SafeInt<T,E>& operator&= (SafeInt<U, E> rhs) throw()
^ SafeInt<T,E> operator^ (SafeInt<T,E> rhs) const throw()
^ template<typename U>

SafeInt<T,E> operator^ (U rhs) const throw()
^= SafeInt<T,E>& operator^= (SafeInt<T,E> rhs) throw()
^= template<typename U>

SafeInt<T,E>& operator^= (U rhs) throw()
^= template<typename U>

SafeInt<T,E>& operator^= (SafeInt<U, E> rhs) throw()
| SafeInt<T,E> operator| (SafeInt<T,E> rhs) const throw()
| template<typename U>

SafeInt<T,E> operator| (U rhs) const throw()
|= SafeInt<T,E>& operator|= (SafeInt<T,E> rhs) throw()
|= template<typename U>

SafeInt<T,E>& operator|= (U rhs) throw()
|= template<typename U>

SafeInt<T,E>& operator|= (SafeInt<U, E> rhs) throw()

Uwagi

Klasa SafeInt chroni przed przepełnieniem liczb całkowitych w operacjach matematycznych. Rozważ na przykład dodanie dwóch 8-bitowych liczb całkowitych: jedna ma wartość 200, a druga ma wartość 100. Prawidłowa operacja matematyczna to 200 + 100 = 300. Jednak ze względu na 8-bitowy limit liczby całkowitej, górny bit zostanie utracony, a kompilator zwróci 44 (300– 28) w wyniku. Każda operacja, która zależy od tego równania matematycznego, spowoduje wygenerowanie nieoczekiwanego zachowania.

Klasa SafeInt sprawdza, czy występuje przepełnienie arytmetyczne, czy też kod próbuje podzielić przez zero. W obu przypadkach klasa wywołuje program obsługi błędów, aby ostrzec program o potencjalnym problemie.

Ta klasa umożliwia również porównanie dwóch różnych typów liczb całkowitych, o ile są to SafeInt obiekty. Zazwyczaj podczas porównywania należy najpierw przekonwertować liczby na ten sam typ. Rzutowanie jednej liczby do innego typu często wymaga sprawdzenia, czy nie ma utraty danych.

Tabela Operatory w tym temacie zawiera listę operatorów matematycznych i porównawczych obsługiwanych przez klasę SafeInt . Większość operatorów matematycznych zwraca SafeInt obiekt typu T.

Operacje porównania między typem całkowitym a SafeInt mogą być wykonywane w obu kierunkach. Na przykład oba SafeInt<int>(x) < y elementy i y> SafeInt<int>(x) są prawidłowe i będą zwracać ten sam wynik.

Wiele operatorów binarnych nie obsługuje używania dwóch różnych SafeInt typów. Jednym z przykładów jest & operator . SafeInt<T, E> & int jest obsługiwany, ale SafeInt<T, E> & SafeInt<U, E> nie. W tym ostatnim przykładzie kompilator nie wie, jaki typ parametru ma być zwracany. Jednym z rozwiązań tego problemu jest rzutowanie drugiego parametru z powrotem do typu podstawowego. Za pomocą tych samych parametrów można to zrobić za SafeInt<T, E> & (U)SafeInt<U, E>pomocą polecenia .

Uwaga

W przypadku wszystkich operacji bitowych dwa różne parametry powinny mieć ten sam rozmiar. Jeśli rozmiary będą się różnić, kompilator zgłosi wyjątek ASSERT . Wyniki tej operacji nie mogą być dokładne. Aby rozwiązać ten problem, rzutuj mniejszy parametr do momentu, gdy będzie on taki sam jak większy parametr.

W przypadku operatorów przesunięcia przesunięcie większej liczby bitów niż istnieje dla typu szablonu spowoduje zgłoszenie wyjątku ASSERT. Nie będzie to miało żadnego wpływu w trybie wydania. Mieszanie dwóch typów parametrów Sejf Int jest możliwe dla operatorów przesunięcia, ponieważ typ zwracany jest taki sam jak oryginalny typ. Liczba po prawej stronie operatora wskazuje tylko liczbę bitów do przesunięcia.

W przypadku porównania logicznego z obiektem Sejf Int porównanie jest ściśle arytmetyczne. Rozważmy na przykład następujące wyrażenia:

  • SafeInt<uint>((uint)~0) > -1

  • ((uint)~0) > -1

Pierwsza instrukcja jest rozpoznawana jako true, ale druga instrukcja jest rozpoznawana jako false. Negacja bitowa 0 jest 0xFFFFFFFF. W drugiej instrukcji domyślny operator porównania porównuje 0xFFFFFFFF z 0xFFFFFFFF i uważa je za równe. Operator porównania dla SafeInt klasy zdaje sobie sprawę, że drugi parametr jest ujemny, podczas gdy pierwszy parametr jest niepodpisany. W związku z tym, mimo że reprezentacja bitowa jest identyczna, operator logiczny zdaje sobie sprawę, SafeInt że liczba całkowita bez znaku jest większa niż -1.

Należy zachować ostrożność podczas używania SafeInt klasy razem z operatoremternary ?: . Rozważ następujący wiersz kodu.

Int x = flag ? SafeInt<unsigned int>(y) : -1;

Kompilator konwertuje go na następujący:

Int x = flag ? SafeInt<unsigned int>(y) : SafeInt<unsigned int>(-1);

Jeśli flag parametr to false, kompilator zgłasza wyjątek zamiast przypisywać wartość -1 do x. W związku z tym, aby uniknąć tego zachowania, prawidłowy kod do użycia jest następujący wiersz.

Int x = flag ? (int) SafeInt<unsigned int>(y) : -1;

T można U przypisać typ logiczny, typ znaku lub typ liczby całkowitej. Typy liczb całkowitych mogą być podpisane lub niepodpisane, a dowolny rozmiar z 8 bitów do 64 bitów.

Uwaga

SafeInt Mimo że klasa akceptuje dowolny rodzaj liczby całkowitej, działa wydajniej z niepodpisanymi typami.

E to mechanizm obsługi błędów, który SafeInt używa. Dwie mechanizmy obsługi błędów są dostarczane z biblioteką Sejf Int. Domyślne zasady to SafeIntErrorPolicy_SafeIntException, która zgłasza wyjątek klasy Sejf IntException w przypadku wystąpienia błędu. Inne zasady to SafeIntErrorPolicy_InvalidParameter, która zatrzymuje program w przypadku wystąpienia błędu.

Istnieją dwie opcje dostosowywania zasad błędów. Pierwszą opcją jest ustawienie parametru E podczas tworzenia elementu SafeInt. Użyj tej opcji, jeśli chcesz zmienić zasady obsługi błędów tylko dla jednego SafeInt. Drugą opcją jest zdefiniowanie _SAFEINT_DEFAULT_ERROR_POLICY jako dostosowanej klasy obsługi błędów przed dołączeniem biblioteki SafeInt . Użyj tej opcji, jeśli chcesz zmienić domyślne zasady obsługi błędów dla wszystkich wystąpień SafeInt klasy w kodzie.

Uwaga

Niestandardowa klasa, która obsługuje błędy z biblioteki Sejf Int, nie powinna zwracać kontroli do kodu, który nazwał procedurę obsługi błędów. Po wywołaniu procedury obsługi błędów wynik SafeInt operacji nie może być zaufany.

Hierarchia dziedziczenia

SafeInt

Wymagania

Nagłówek: Sejf Int.hpp

Uwaga

Najnowsza wersja tej biblioteki znajduje się w https://github.com/dcleblanc/SafeIntlokalizacji . Sklonuj bibliotekę i dołącz bibliotekę Sejf Int.hpp, aby użyć biblioteki Sejf Int. Preferuj to repozytorium GitHub, aby <safeint.h>. jest to nowoczesna wersja <pliku safeint.h> , która zawiera niewielką liczbę poprawek usterek, używa nowoczesnych funkcji języka C++ w celu uzyskania bardziej wydajnego kodu i jest przenośna do dowolnej platformy przy użyciu kompilatorów gcc, clang lub Intel.

Przykład

#include "SafeInt.hpp" // set path to your clone of the SafeInt GitHub repo (https://github.com/dcleblanc/SafeInt)

int main()
{
    int divisor = 3;
    int dividend = 6;
    int result;

    bool success = SafeDivide(dividend, divisor, result); // result = 2
    success = SafeDivide(dividend, 0, result); // expect fail. result isn't modified.
}

Przestrzeń nazw: brak

SafeInt::SafeInt

SafeInt Tworzy obiekt.

SafeInt() throw

SafeInt (const T& i) throw ()

SafeInt (bool b) throw ()

template <typename U>
SafeInt (const SafeInt <U, E>& u)

I template <typename U>
SafeInt (const U& i)

Parametry

i
[in] Wartość nowego SafeInt obiektu. Musi to być parametr typu T lub U, w zależności od konstruktora.

b
[in] Wartość logiczna dla nowego SafeInt obiektu.

u
[in] Typ SafeInt U. Nowy SafeInt obiekt będzie miał taką samą wartość jak u, ale będzie miał typ T.

U Typ danych przechowywanych w obiekcie SafeInt. Może to być typ logiczny, znak lub liczba całkowita. Jeśli jest to typ liczb całkowitych, może być podpisany lub niepodpisany i mieć od 8 do 64 bitów.

Uwagi

Parametr wejściowy konstruktora i lub u musi być typem logicznym, znakiem lub liczbą całkowitą. Jeśli jest to inny typ parametru, SafeInt klasa wywołuje static_assert , aby wskazać nieprawidłowy parametr wejściowy.

Konstruktory używające typu U szablonu automatycznie konwertują parametr wejściowy na typ określony przez T. Klasa SafeInt konwertuje dane bez utraty danych. Zgłasza on program obsługi E błędów, jeśli nie może przekonwertować danych na typ T bez utraty danych.

Jeśli tworzysz element SafeInt na podstawie parametru logicznego, musisz natychmiast zainicjować wartość. Nie można skonstruować elementu SafeInt przy użyciu kodu SafeInt<bool> sb;. Spowoduje to wygenerowanie błędu kompilacji.