Класс SafeInt

Расширяет примитивы целых чисел, чтобы предотвратить переполнение целого числа, и позволяет сравнивать разные типы целых чисел.

Примечание.

Последняя версия библиотеки Сейф Int находится по адресуhttps://github.com/dcleblanc/SafeInt. Чтобы использовать библиотеку Сейф Int, клонируйте репозиторий и#include "SafeInt.hpp"

Синтаксис

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

Параметры

T
Тип целого числа или логического параметра, который заменяет SafeInt.

E
Перечисляемый тип данных, который определяет политику обработки ошибок.

U
Тип целого числа или логического параметра для дополнительного операнда.

rhs
[in] Входной параметр, представляющий значение справа от оператора в нескольких отдельных функциях.

i
[in] Входной параметр, представляющий значение справа от оператора в нескольких отдельных функциях.

bits
[in] Входной параметр, представляющий значение справа от оператора в нескольких отдельных функциях.

Участники

Открытые конструкторы

Имя Описание
SafeInt::SafeInt Конструктор по умолчанию.

Операторы присваивания

Имя. Синтаксис
= 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()

Операторы приведения

Имя. Синтаксис
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
длинный 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

Операторы сравнения

Имя. Синтаксис
< 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()

Арифметические операторы

Имя. Синтаксис
+ 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)

Логические операторы

Имя. Синтаксис
! 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()

Замечания

Класс SafeInt защищает от переполнения целого числа в математических операциях. Например, добавьте два 8-битовых целых числа: одно из них со значением 200, а второе со значением 100. Правильной математической операцией будет 200 + 100 = 300. Тем не менее из-за ограничения 8-битового целого числа верхний бит будет утерян и компилятор вернет 44 (300-28) в качестве результата. Любая операция, которая зависит от этого математического уравнения, создаст непредвиденное поведение.

Класс SafeInt проверяет, происходит ли арифметическое переполнение или предпринимается ли в коде попытка деления на ноль. В обоих случаях класс вызывает обработчик ошибок, чтобы предупредить программу о потенциальных проблемах.

Этот класс также позволяет сравнить два различных типа целых чисел, пока они являются объектами SafeInt. Как правило, при сравнении необходимо сначала преобразовать числа в один и тот же тип. При приведении одного числа в другой тип часто требуется выполнить проверку, чтобы убедиться в отсутствии потери данных.

В таблице "Операторы" в этом разделе перечислены математические операторы и операторы сравнения, поддерживаемые классом SafeInt. Большинство математических операторов возвращают объект SafeInt типа T.

Операции сравнения между SafeInt и целочисленным типом данных могут выполняться в любом направлении. Например, SafeInt<int>(x) < y и y> SafeInt<int>(x) являются допустимыми и вернут один и тот же результат.

Многие двоичные операторы не поддерживают использование двух разных SafeInt типов. Примером этого является оператор &. SafeInt<T, E> & int поддерживается, но SafeInt<T, E> & SafeInt<U, E> не поддерживается. В последнем примере компилятору не удалось определить тип возвращаемого параметра. Одно из решений этой проблемы состоит в приведении второго параметра в базовый тип. Используя те же параметры, это можно сделать с помощью SafeInt<T, E> & (U)SafeInt<U, E>.

Примечание.

Для любых битовых операций два различных параметра должны быть одного размера. Если размеры отличаются, компилятор выдаст исключение ASSERT. Результаты этой операции не могут быть точными. Чтобы устранить эту проблему, приведение меньшего параметра до тех пор, пока не будет тот же размер, что и более крупный параметр.

Для операторов сдвига выполнение сдвига на большее количество бит, чем это возможно для типа шаблона, приведет к исключению ASSERT. Это не будет действовать в режиме выпуска. Для операторов сдвига возможно сочетание двух типов параметров SafeInt, так как тип возвращаемого значения совпадает с исходным. Число справа от оператора лишь указывает количество битов для сдвига.

При выполнении логического сравнения с объектом Сейф Int сравнение строго арифметично. Например, рассмотрим эти выражения:

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

  • ((uint)~0) > -1

Первая инструкция разрешается true, но вторая инструкция разрешается false. Результат битового отрицания 0 — 0xFFFFFFFF. Во второй инструкции оператор сравнения по умолчанию сравнивает 0xFFFFFFFF с 0xFFFFFFFF и рассматривает их как равные. Оператор сравнения для класса SafeInt определяет, что второй параметр является отрицательным, тогда как первый параметр — без знака. Таким образом, несмотря на то, что битовое представление идентично, логический оператор SafeInt определяет, что целое число без знака больше, чем значение -1.

Будьте внимательны при использовании класса SafeInt вместе с тернарным оператором ?:. Рассмотрим приведенную ниже строку кода.

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

Компилятор преобразует ее в следующий код:

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

Если flag имеет значение false, компилятор создает исключение вместо присвоения x значения -1. Таким образом, чтобы избежать этого, воспользуйтесь правильным кодом, приведенным в следующей строке.

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

T и U можно назначить логический тип, тип символа или целочисленный тип. Целочисленные типы могут быть со знаком или без него, а также любого размера — от 8 до 64 бит.

Примечание.

Несмотря на то, что класс SafeInt принимает любой целочисленный тип, он выполняется эффективнее с типами без знака.

E — это механизм обработки ошибок, используемый SafeInt. С библиотекой SafeInt предоставляются два механизма обработки ошибок. Политика по умолчанию — SafeIntErrorPolicy_SafeIntException, которая вызывает исключение Класс SafeIntException при возникновении ошибки. Другой политикой является SafeIntErrorPolicy_InvalidParameter, которая останавливает программу, если произошла ошибка.

Есть два варианта настройки политики ошибок. Первый вариант — задать параметр E при создании SafeInt. Используйте этот вариант, если необходимо изменить политику обработки ошибок только для одного SafeInt. Другой вариант — определить _SAFEINT_DEFAULT_ERROR_POLICY настраиваемым классом обработки ошибок до добавления библиотеки SafeInt. Используйте этот вариант, когда необходимо изменить политику обработки ошибок по умолчанию для всех экземпляров класса SafeInt в вашем коде.

Примечание.

Настраиваемый класс, который обрабатывает ошибки из библиотеки SafeInt, не должен возвращать элемент управления в код, который вызвал обработчик ошибок. После вызова SafeInt обработчика ошибок результат операции не может быть доверенным.

Иерархия наследования

SafeInt

Requirements

Заголовок: Сейф Int.hpp

Примечание.

Последняя версия этой библиотеки размещена здесь: https://github.com/dcleblanc/SafeInt. Клонируйте библиотеку и включите Сейф Int.hpp для использования библиотеки Сейф Int. Предпочитайте этот репозиторий <GitHub для safeint.h>. Это современная версия <safeint.h> , которая включает небольшое количество исправлений ошибок, использует современные функции C++, что приводит к более эффективному коду и переносится на любую платформу с помощью gcc, clang или компиляторов Intel.

Пример

#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.
}

Пространство имен: нет

SafeInt::SafeInt

Формирует объект 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)

Параметры

i
[in] Значение для нового объекта SafeInt. Это должен быть параметр типа T или U в зависимости от конструктора.

b
[in] Логическое значение для нового объекта SafeInt.

u
[in] Объект SafeInt типа U. Новый объект SafeInt будет иметь то же значение, что и u, но будет иметь тип T.

U Тип данных, хранящихся в объекте SafeInt. Это может быть логический тип, тип символа или целочисленный тип. Если это целочисленный тип, он может быть подписан или без знака и быть от 8 до 64 бит.

Замечания

Входной параметр для конструктора, i или u, должен быть логическим типом, типом символа или целочисленным типом. Если это другой тип параметра, SafeInt класс вызывает static_assert , чтобы указать недопустимый входной параметр.

Конструкторы, использующие тип шаблона U, автоматически преобразовывают входной параметр в тип, заданный параметром T. Класс SafeInt преобразовывает данные без потери. Он сообщает обработчику E ошибок, если он не может преобразовать данные в тип T без потери данных.

Если вы создаете SafeInt из логического параметра, необходимо немедленно инициализировать значение. Невозможно создать SafeInt код с помощью кода SafeInt<bool> sb;. Это приведет к ошибке компиляции.