SafeInt – třída
Rozšiřuje celá čísla, aby se zabránilo přetečení celého čísla a umožňuje porovnat různé typy celých čísel.
Poznámka:
Nejnovější verze knihovny SafeInt se nachází na adrese https://github.com/dcleblanc/SafeInt. Pokud chcete použít knihovnu SafeInt, naklonujte úložiště a #include "SafeInt.hpp"
Syntaxe
template<typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY>
class SafeInt;
Parametry
T
Typ celočíselného nebo logického parametru, který SafeInt
nahrazuje.
E
Výčtový datový typ, který definuje zásady zpracování chyb.
U
Typ celočíselného nebo logického parametru pro sekundární operand.
rhs
[v] Vstupní parametr, který představuje hodnotu na pravé straně operátoru v několika samostatných funkcích.
já
[v] Vstupní parametr, který představuje hodnotu na pravé straně operátoru v několika samostatných funkcích.
bity
[v] Vstupní parametr, který představuje hodnotu na pravé straně operátoru v několika samostatných funkcích.
Členové
Veřejné konstruktory
Název | Popis |
---|---|
SafeInt::SafeInt | Výchozí konstruktor. |
Operátory přiřazení
Název | Syntaxe |
---|---|
= | 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() |
Operátory přetypování
Název | Syntaxe |
---|---|
bool | operator bool() throw() |
char | operator char() const |
podepsaný znak | operator signed char() const |
unsigned char | operator unsigned char() const |
__int16 | operator __int16() const |
__int16 bez znaménka | operator unsigned __int16() const |
__int32 | operator __int32() const |
nepodepsaný __int32 | operator unsigned __int32() const |
long | operator long() const |
unsigned long | operator unsigned long() const |
__int64 | operator __int64() const |
nepodepsaný __int64 | operator unsigned __int64() const |
wchar_t | operator wchar_t() const |
Operátory porovnání
Název | Syntaxe |
---|---|
< | 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() |
Aritmetické operátory
Název | Syntaxe |
---|---|
+ | 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) |
Logické operátory
Název | Syntaxe |
---|---|
! | 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() |
Poznámky
Třída SafeInt
chrání před přetečením celého čísla v matematických operacích. Zvažte například přidání dvou 8bitových celých čísel: jedno má hodnotu 200 a druhá má hodnotu 100. Správná matematická operace by byla 200 + 100 = 300. Kvůli 8bitovému celočíselnému limitu se však horní bit ztratí a kompilátor vrátí jako výsledek hodnotu 44 (300 –28). Jakákoli operace, která závisí na této matematické rovnici, vygeneruje neočekávané chování.
Třída SafeInt
zkontroluje, zda dojde k aritmetickému přetečení nebo zda se kód pokusí dělit nulou. V obou případech třída volá obslužnou rutinu chyby, která upozorní program na potenciální problém.
Tato třída také umožňuje porovnat dva různé typy celých čísel, pokud jsou SafeInt
objekty. Při porovnávání je obvykle nutné čísla nejprve převést na stejný typ. Přetypování jednoho čísla na jiný typ často vyžaduje kontroly, aby se zajistilo, že nedojde ke ztrátě dat.
Tabulka Operators v tomto tématu uvádí matematické a porovnávací operátory podporované SafeInt
třídou. Většina matematických operátorů vrací SafeInt
objekt typu T
.
Operace porovnání mezi celočíselným typem SafeInt
lze provádět v obou směrech. Například obě SafeInt<int>(x) < y
a y> SafeInt<int>(x)
jsou platné a vrátí stejný výsledek.
Mnoho binárních operátorů nepodporuje použití dvou různých SafeInt
typů. Jedním z příkladů je &
operátor. SafeInt<T, E> & int
se podporuje, ale SafeInt<T, E> & SafeInt<U, E>
není. V druhém příkladu kompilátor neví, jaký typ parametru se má vrátit. Jedním z řešení tohoto problému je přetypování druhého parametru zpět na základní typ. Pomocí stejných parametrů to lze provést pomocí SafeInt<T, E> & (U)SafeInt<U, E>
.
Poznámka:
Pro všechny bitové operace by měly mít dva různé parametry stejnou velikost. Pokud se velikosti liší, kompilátor vyvolá výjimku ASSERT . Výsledky této operace nelze zaručit, že budou přesné. Pokud chcete tento problém vyřešit, přetypujte menší parametr, dokud nebude stejný jako větší parametr.
U operátorů směny vyvolá posun více bitů, než existuje pro typ šablony, vyvolá výjimku ASSERT. To nebude mít žádný vliv v režimu vydání. Pro operátory směn je možné kombinovat dva typy parametrů SafeInt, protože návratový typ je stejný jako původní typ. Číslo na pravé straně operátoru označuje pouze počet bitů, které se mají posunout.
Při logickém porovnání s objektem SafeInt je porovnání přísně aritmetické. Představte si například tyto výrazy:
SafeInt<uint>((uint)~0) > -1
((uint)~0) > -1
První příkaz se přeloží na true
, ale druhý příkaz se přeloží na false
. Bitové negace 0 je 0xFFFFFFFF. Ve druhém příkazu výchozí relační operátor porovnává 0xFFFFFFFF s 0xFFFFFFFF a považuje je za stejné. Relační operátor třídy SafeInt
zjistí, že druhý parametr je záporný, zatímco první parametr je nepodepsaný. I když je bitová reprezentace identická, SafeInt
logický operátor si uvědomuje, že celé číslo bez znaménka je větší než -1.
Při použití SafeInt
třídy spolu s ternárním operátorem ?:
buďte opatrní. Podívejte se na následující řádek kódu.
Int x = flag ? SafeInt<unsigned int>(y) : -1;
Kompilátor ho převede na toto:
Int x = flag ? SafeInt<unsigned int>(y) : SafeInt<unsigned int>(-1);
Pokud flag
je false
, kompilátor vyvolá výjimku místo přiřazení hodnoty -1 k x
. Abyste se tomuto chování vyhnuli, je správný kód, který se má použít, následující řádek.
Int x = flag ? (int) SafeInt<unsigned int>(y) : -1;
T
a U
může být přiřazen logický typ, typ znaku nebo celočíselné typy. Celočíselné typy mohou být podepsány nebo bez znaménka a libovolnou velikost od 8 bitů do 64 bitů.
Poznámka:
SafeInt
I když třída přijímá jakýkoli druh celého čísla, provádí efektivněji s nepodepsanými typy.
E
je mechanismus zpracování chyb, který SafeInt
se používá. V knihovně SafeInt jsou k dispozici dva mechanismy zpracování chyb. Výchozí zásada je SafeIntErrorPolicy_SafeIntException
, která vyvolá výjimku Třídy SafeIntException , když dojde k chybě. Další zásada je SafeIntErrorPolicy_InvalidParameter
, která program zastaví, pokud dojde k chybě.
Existují dvě možnosti přizpůsobení zásad chyb. První možností je nastavit parametr E
při vytváření .SafeInt
Tuto možnost použijte, pokud chcete změnit zásady zpracování chyb pouze pro jednu SafeInt
. Druhou možností je definovat _SAFEINT_DEFAULT_ERROR_POLICY jako přizpůsobenou třídu zpracování chyb před zahrnutím SafeInt
knihovny. Tuto možnost použijte, pokud chcete změnit výchozí zásady zpracování chyb pro všechny instance SafeInt
třídy v kódu.
Poznámka:
Přizpůsobená třída, která zpracovává chyby z knihovny SafeInt, by neměla vrátit ovládací prvek do kódu, který volal obslužnou rutinu chyby. Po zavolání obslužné rutiny chyby nemůže být výsledek SafeInt
operace důvěryhodný.
Hierarchie dědičnosti
SafeInt
Požadavky
Hlavička: SafeInt.hpp
Poznámka:
Nejnovější verze této knihovny se nachází na adrese https://github.com/dcleblanc/SafeInt. Naklonujte knihovnu a zahrňte SafeInt.hpp pro použití knihovny SafeInt. Upřednostňujte toto úložiště GitHubu před <safeint.h>. Jedná se o moderní verzi safeint.h>, která obsahuje malý počet oprav chyb, používá moderní funkce jazyka C++, což vede k efektivnějšímu <kódu a je přenositelný na libovolnou platformu pomocí kompilátorů gcc, clang nebo Intel.
Příklad
#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.
}
Obor názvů: žádný
SafeInt::SafeInt
SafeInt
Vytvoří objekt.
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
[v] Hodnota nového SafeInt
objektu. To musí být parametr typu T nebo U v závislosti na konstruktoru.
b
[v] Logická hodnota nového SafeInt
objektu.
u
[v] A SafeInt
typu U. Nový SafeInt
objekt bude mít stejnou hodnotu jako u, ale bude mít typ T.
U
Typ dat uložených v souboru SafeInt
. Může to být logický typ, znak nebo celé číslo. Pokud se jedná o celočíselné číslo, může být podepsáno nebo bez znaménka a může být mezi 8 a 64 bity.
Poznámky
Vstupním parametrem konstruktoru, i nebo u musí být logický typ, znak nebo celé číslo. Pokud se jedná o jiný typ parametru, SafeInt
třída volá static_assert označují neplatný vstupní parametr.
Konstruktory, které používají typ U
šablony, automaticky převedou vstupní parametr na typ určený T
. Třída SafeInt
převede data bez ztráty dat. Hlásí obslužnou rutinu E
chyby, pokud nemůže převést data na typ T
bez ztráty dat.
Pokud vytvoříte SafeInt
z logického parametru, musíte hodnotu inicializovat okamžitě. Nelze vytvořit SafeInt
pomocí kódu SafeInt<bool> sb;
. Tím se vygeneruje chyba kompilace.