SafeInt, classe
Étend les primitifs entiers afin d’éviter les débordements d’entiers et permet de comparer les différents types d’entiers.
Remarque
La dernière version de la bibliothèque SafeInt se trouve à l’adresse https://github.com/dcleblanc/SafeInt. Pour utiliser la bibliothèque SafeInt, clonez le dépôt et #include "SafeInt.hpp"
Syntaxe
template<typename T, typename E = _SAFEINT_DEFAULT_ERROR_POLICY>
class SafeInt;
Paramètres
T
Le type d’entier ou de paramètre booléen remplacé par SafeInt
.
E
Un type de données énumérées qui définit la stratégie de gestion des erreurs.
U
Le type d’entier ou de paramètre booléen pour l’opérande secondaire.
rhs
[in] Un paramètre d’entrée qui représente la valeur à droite de l’opérateur dans plusieurs fonctions autonomes.
i
[in] Un paramètre d’entrée qui représente la valeur à droite de l’opérateur dans plusieurs fonctions autonomes.
bits
[in] Un paramètre d’entrée qui représente la valeur à droite de l’opérateur dans plusieurs fonctions autonomes.
Membres
Constructeurs publics
Nom | Description |
---|---|
SafeInt::SafeInt | Constructeur par défaut. |
Opérateurs d’assignation
Nom | 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() |
Opérateurs de casting
Nom | Syntaxe |
---|---|
bool | operator bool() throw() |
char | operator char() const |
signed char | operator signed char() const |
unsigned char | operator unsigned char() const |
__int16 | operator __int16() const |
unsigned __int16 | operator unsigned __int16() const |
__int32 | operator __int32() const |
unsigned __int32 | operator unsigned __int32() const |
long | operator long() const |
unsigned long | operator unsigned long() const |
__int64 | operator __int64() const |
unsigned __int64 | operator unsigned __int64() const |
wchar_t | operator wchar_t() const |
Opérateurs de comparaison
Nom | 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() |
Opérateurs arithmétiques
Nom | 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) |
Opérateurs logiques
Nom | 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() |
Notes
La classe SafeInt
protège contre les dépassements sur les entiers dans les opérations mathématiques. Par exemple, vous pouvez ajouter deux entiers 8 bits, l’un avec une valeur de 200 et l’autre avec une valeur de 100. L’opération mathématique correcte serait 100 + 200 = 300. Toutefois, en raison de la limitation de l’entier 8 bits, le bit supérieur sera perdu et le compilateur retournera 44 (300 - 28) comme résultat. Toute opération dépendant de cette équation mathématique générera un comportement inattendu.
La classe SafeInt
vérifie si un débordement arithmétique se produit ou si le code tente de diviser par zéro. Dans les deux cas, la classe appelle le gestionnaire d’erreurs pour avertir le programme de ce problème potentiel.
Cette classe vous permet également de comparer deux différents types d’entiers, dès lors qu’il s’agit d’objets SafeInt
. En règle générale, lorsque vous effectuez une comparaison, vous devez d’abord convertir les nombres en le même type. La conversion d’un nombre à un autre type requiert généralement des vérifications pour s’assurer qu’aucune perte de données ne s’est produite.
La table des opérateurs dans cette rubrique répertorie les opérateurs mathématiques et de comparaison pris en charge par la classe SafeInt
. La plupart des opérateurs mathématiques retournent un objet SafeInt
de type T
.
Des opérations de comparaison entre un SafeInt
et un type intégral peuvent être réalisées dans les deux sens. Par exemple, SafeInt<int>(x) < y
et y> SafeInt<int>(x)
sont valides et retournent le même résultat.
De nombreux opérateurs binaires ne prennent pas en charge l’utilisation de deux types différents SafeInt
. L’opérateur &
en est un exemple. SafeInt<T, E> & int
est pris en charge, mais SafeInt<T, E> & SafeInt<U, E>
ce n’est pas le cas. Dans ce dernier exemple, le compilateur ne sait pas quel type de paramètre retourner. L’une des solutions à ce problème consiste à effectuer un cast en retour du deuxième paramètre vers le type de base. En utilisant les mêmes paramètres, cela peut être effectué avec SafeInt<T, E> & (U)SafeInt<U, E>
.
Remarque
Pour toutes les opérations au niveau du bit, les deux paramètres doivent être de la même taille. Si les tailles sont différentes, le compilateur générera une exception ASSERT. Les résultats de cette opération ne peuvent pas être sûrs d’être exacts. Pour résoudre ce problème, cassez le paramètre plus petit jusqu’à ce qu’il soit de la même taille que le paramètre le plus grand.
Pour les opérateurs de décalage, le décalage d’un plus grand nombre de bits qu’il en existe pour le type de modèle lève une exception ASSERT. Cela n’aura aucun effet en mode Release. Les opérateurs de décalage peuvent mélanger deux types de paramètres SafeInt, car le type de retour est identique au type d’origine. Le nombre situé à droite de l’opérateur indique uniquement le nombre de bits à décaler.
Lorsque vous effectuez une comparaison logique avec un objet SafeInt, la comparaison est strictement arithmétique. Prenons par exemple ces expressions :
SafeInt<uint>((uint)~0) > -1
((uint)~0) > -1
La première instruction est true
résolue en , mais la deuxième instruction est résolue en false
. La négation d’opération de bits de 0 est 0xFFFFFFFF. Dans la deuxième instruction, l’opérateur de comparaison par défaut compare 0xFFFFFFFF à 0xFFFFFFFF et les considère comme égaux. L’opérateur de comparaison de la classe SafeInt
se rend compte que le deuxième paramètre est négatif, tandis que le premier paramètre n’est pas signé. Par conséquent, bien que la représentation binaire soit identique, l’opérateur logique SafeInt
se rend compte que l’entier non signé est supérieur à -1.
Soyez prudent lorsque vous utilisez la classe SafeInt
avec l’opérateur ternaire ?:
. Examinez la ligne de code suivante.
Int x = flag ? SafeInt<unsigned int>(y) : -1;
Le compilateur la convertit ainsi :
Int x = flag ? SafeInt<unsigned int>(y) : SafeInt<unsigned int>(-1);
Si flag
est false
, le compilateur lève une exception au lieu d’affecter la valeur -1 à x
. Par conséquent, pour éviter ce comportement, le code approprié à utiliser est la ligne suivante.
Int x = flag ? (int) SafeInt<unsigned int>(y) : -1;
T
et U
peuvent avoir un type booléen, un type de caractère ou un type entier. Les types d’entier peuvent être signés ou non signés et de toutes tailles, comprises entre 8 bits et 64 bits.
Remarque
Bien que la classe SafeInt
accepte tous les types d’entier, elle effectue ses tâches plus efficacement avec les types non signés.
E
est le mécanisme de gestion des erreurs utilisé par SafeInt
. Deux mécanismes de gestion des erreurs sont fournis avec la bibliothèque SafeInt. La stratégie par défaut est SafeIntErrorPolicy_SafeIntException
, qui lève une exception SafeIntException Class lorsqu’une erreur se produit. L’autre stratégie est SafeIntErrorPolicy_InvalidParameter
, qui arrête le programme si une erreur se produit.
Deux options sont disponibles pour personnaliser la stratégie d’erreur. La première option consiste à définir le paramètre E
lorsque vous créez un SafeInt
. Utilisez cette option lorsque vous souhaitez modifier la stratégie de gestion des erreurs pour un seul SafeInt
. L’autre option consiste à définir _SAFEINT_DEFAULT_ERROR_POLICY comme votre classe de gestion des erreurs personnalisée avant d’inclure la bibliothèque SafeInt
. Utilisez cette option pour modifier la stratégie par défaut de gestion des erreurs pour toutes les instances de la classe SafeInt
de votre code.
Remarque
Une classe personnalisée qui gère les erreurs à partir de la bibliothèque SafeInt ne doit pas retourner le contrôle au code qui a appelé le gestionnaire d’erreurs. Une fois le gestionnaire d’erreurs appelé, le résultat de l’opération SafeInt
ne peut pas être approuvé.
Hiérarchie d'héritage
SafeInt
Spécifications
En-tête : SafeInt.hpp
Remarque
La dernière version de cette bibliothèque se trouve dans https://github.com/dcleblanc/SafeInt. Clonez la bibliothèque et incluez SafeInt.hpp pour utiliser la bibliothèque SafeInt. Préférez ce dépôt GitHub à <safeint.h>. il s’agit d’une version moderne de <safeint.h> qui inclut un petit nombre de correctifs de bogues, utilise des fonctionnalités modernes de C++ qui entraînent un code plus efficace et est portable pour n’importe quelle plateforme utilisant gcc, clang ou des compilateurs Intel.
Exemple
#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.
}
Namespace : aucun
SafeInt::SafeInt
Construit un objet SafeInt
.
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)
Paramètres
i
[in] La valeur du nouvel objet SafeInt
. Il doit s’agir d’un paramètre de type T ou U, en fonction du constructeur.
b
[in] La valeur booléenne du nouvel objet SafeInt
.
u
[in] Un SafeInt
de type U. Le nouvel objet SafeInt
aura la même valeur que le type U, mais sera de type T.
U
Type de données stockées dans le SafeInt
. Il peut s’agit d’un type booléen, d’un type de caractère ou d’un type entier. S’il s’agit d’un type entier, il peut être signé ou non signé et être compris entre 8 et 64 bits.
Notes
Le paramètre d’entrée pour le constructeur, i ou u, doit être un type booléen, de caractère ou entier. S’il s’agit d’un autre type de paramètre, la SafeInt
classe appelle static_assert pour indiquer un paramètre d’entrée non valide.
Les constructeurs qui utilisent le type de modèle U
convertissent automatiquement le paramètre d’entrée du type spécifié par T
. La classe SafeInt
convertit les données sans aucune perte de données. Il signale au gestionnaire E
d’erreurs s’il ne peut pas convertir les données en type T
sans perte de données.
Si vous créez un SafeInt
à partir d’un paramètre booléen, vous devez initialiser la valeur immédiatement. Vous ne pouvez pas construire d’utilisation SafeInt
du code SafeInt<bool> sb;
. Cela générera une erreur de compilation.