Шаблон C++ для безопасных целочисленных бросков

Я бы использовал .Equals() для сравнения вместо ==.

Примерно так:

MyClass item = MyList.Find(item => item.name.Equals("foo"));

В частности, потому что он дает вам такие опции, как StringComparison, что просто потрясающе. Пример:

MyClass item = MyList.Find(item => item.name.Equals("foo", StringComparison.InvariantCultureIgnoreCase);

Это позволяет вашему коду игнорировать специальные символы, прописные и строчные. Есть еще варианты.

11
задан JSBձոգչ 28 August 2009 в 20:21
поделиться

7 ответов

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

5
ответ дан 3 December 2019 в 01:24
поделиться

Вы можете получить минимальные и максимальные безопасные значения (и много другой информации) для любого основного типа гораздо более элегантным способом, используя std :: numeric_limits шаблон, например std :: numeric_limits :: max () . Вам нужно будет включить .

Ссылка: http://www.cplusplus.com/reference/std/limits/numeric_limits/

12
ответ дан 3 December 2019 в 01:24
поделиться

Возможно ли повышение? В таком случае попробуйте boost :: numeric_cast <> . Похоже, он обеспечивает характеристики, которые вы ищете.

11
ответ дан 3 December 2019 в 01:24
поделиться

Я думаю, что сейчас они работают, независимо от того, используете ли вы дополнение до двух или нет. Пожалуйста, тщательно протестируйте, прежде чем использовать его. Они дают следующие результаты. Каждая строка дает один сбой утверждения (просто измените их на исключения по своему усмотрению)

/* unsigned -> signed, overflow */
safe_cast<short>(UINT_MAX);

/* unsigned -> unsigned, overflow */
safe_cast<unsigned char>(ULONG_MAX);

/* signed -> unsigned, overflow */
safe_cast<unsigned long>(-1);

/* signed -> signed, overflow */
safe_cast<signed char>(INT_MAX);

/* always works (no check done) */
safe_cast<long>(INT_MAX);

// giving these assertion failures results
(type)f <= (type)is_signed<To>::v_max
f <= (To)-1
f >= 0
f >= is_signed<To>::v_min && f <= is_signed<To>::v_max

Реализация. Сначала несколько утилит для проверки целочисленных рангов (типы с более высокими рангами могут содержать значения типов с более низким рангом с тем же знаком. И некоторые инструменты продвижения, чтобы иметь возможность определить общий, безопасный тип (это никогда не дают подписанный тип, если задействован беззнаковый тип, если подписанный тип не сможет хранить все значения беззнакового).

/* ranks */
template<typename> struct int_rank;
#define RANK(T, I) template<> struct int_rank<T> \
    { static int const value = I; }

RANK(char, 1); RANK(unsigned char, 1); RANK(signed char, 1); 
RANK(short, 2); RANK(unsigned short, 2);
RANK(int, 3); RANK(unsigned int, 3);
RANK(long, 4); RANK(unsigned long, 4);
#undef RANK

/* usual arith. conversions for ints (pre-condition: A, B differ) */
template<int> struct uac_at;
template<> struct uac_at<1> { typedef int type; };
template<> struct uac_at<2> { typedef unsigned int type; };
template<> struct uac_at<3> { typedef long type; };
template<> struct uac_at<4> { typedef unsigned long type; };

template<typename A, typename B>
struct uac_type { 
    static char (&f(int))[1];
    static char (&f(unsigned int))[2];
    static char (&f(long))[3];
    static char (&f(unsigned long))[4];
    typedef typename uac_at<sizeof f(0 ? A() : B())>::type type; 
};

/* signed games */
template<typename> struct is_signed { static bool const value = false; };
#define SG(X, TT) template<> struct is_signed<X> { \
    static bool const value = true;                \
    static X const v_min = TT##_MIN;               \
    static X const v_max = TT##_MAX;               \
}

SG(signed char, SCHAR); 
SG(short, SHRT); 
SG(int, INT); 
SG(long, LONG); 
#undef SG

template<> struct is_signed<char> { 
    static bool const value = (CHAR_MIN < 0); 
    static char const v_min = CHAR_MIN; // just in case it's signed...
    static char const v_max = CHAR_MAX;
};

Шаблоны преобразования используют их, чтобы выяснить для каждого случая, когда что нужно должно быть выполнено или не выполнено.

template<typename To, typename From, 
         bool to_signed = is_signed<To>::value, 
         bool from_signed = is_signed<From>::value,
         bool rank_fine = (int_rank<To>::value >= int_rank<From>::value)>
struct do_conv;

/* these conversions never overflow, like int -> int, 
 * or  int -> long. */
template<typename To, typename From, bool Sign>
struct do_conv<To, From, Sign, Sign, true> {
    static To call(From f) {
        return (To)f; 
    }
};

template<typename To, typename From>
struct do_conv<To, From, false, false, false> {
    static To call(From f) {
        assert(f <= (To)-1);
        return (To)f;
    }
};

template<typename To, typename From>
struct do_conv<To, From, false, true, true> {
    typedef typename uac_type<To, From>::type type;
    static To call(From f) {
        /* no need to check whether To's positive range will
         * store From's positive range: Because the rank is
         * fine, and To is unsigned. 
         * Fixes GCC warning "comparison is always true" */
        assert(f >= 0);
        return (To)f;
    }
};

template<typename To, typename From>
struct do_conv<To, From, false, true, false> {
    typedef typename uac_type<To, From>::type type;
    static To call(From f) {
        assert(f >= 0 && (type)f <= (type)(To)-1);
        return (To)f;
    }
};

template<typename To, typename From, bool Rank>
struct do_conv<To, From, true, false, Rank> {
    typedef typename uac_type<To, From>::type type;
    static To call(From f) {
        assert((type)f <= (type)is_signed<To>::v_max);
        return (To)f;
    }
};

template<typename To, typename From>
struct do_conv<To, From, true, true, false> {
    static To call(From f) {
        assert(f >= is_signed<To>::v_min && f <= is_signed<To>::v_max);
        return (To)f;
    }
};

template<typename To, typename From>
To safe_cast(From f) { return do_conv<To, From>::call(f); }
7
ответ дан 3 December 2019 в 01:24
поделиться

Как насчет :

template< typename T, typename R > void safe_cast( const T& source, R& result )
{
    R temp = static_cast<R>( source );
    if (static_cast<T> (temp) != source
        || ( temp < 0 && source > 0)
        || ( temp > 0 && source < 0))
    {
        throw IntegerOverflowException( source );
    }
    result = temp;
}

Тогда вы просто проверяете, сработало ли приведение. Убедитесь, что вы вернули то, с чего начали, и что знак не перевернулся.

EDIT: Поскольку комментарий ниже запутался, вот он, форматированный:

int myint (-1);
safe_cast( myint, mychar );
safe_cast( mychar, myuchar ); // Exception is thrown here
safe_cast( myuchar, myint );

Преобразование int в char работает нормально. Приведение от char к unsigned char вызывает исключение (как и должно быть). Я не вижу здесь проблемы.

3
ответ дан 3 December 2019 в 01:24
поделиться

Должно быть, я чего-то упускаю, но разве это не то, что вам нужно?:

// using a more cast-like prototype, if I may:
template<class to, class from> inline
to safe_cast(from f)
{
   to t = static_cast<to>(f);
   if ( t != f ) throw whatever; // no new!
   return t;
}
0
ответ дан 3 December 2019 в 01:24
поделиться

Правильно ли я предполагаю, что в случае, если R подписан, вы пытаетесь заполнить rMax всеми единицами, кроме последнего бита? В этом случае вы должны иметь 0x80 (1000 0000) вместо 0x10 (0001 0000).

Также не похоже, что ваша функция поддерживает отрицательные числа для источника.

Изменить:

Здесь это слегка отредактированная версия, которую я тестировал для преобразования целых чисел в символы:

template< typename T, typename R >
void safe_cast( const T& source, R& result )
{
    // get the maximum safe value of type R
    R rMax = (R) ~0;
    if ( rMax < 0 ) // R is a signed type
    {
        // assume that we're on an 8-bit twos-compliment machine
    rMax = ( 0x80 << ( ( sizeof( R ) - 1 ) * 8 ) );
    if(source >= 0)
        rMax = ~rMax;
    }

    if ( (source >= 0 && ( source & rMax  ) != source) || (source < 0 && (source & rMax) != rMax) )
    {
        throw new IntegerOverflowException( source );
    }

    result = static_cast<R>( source );
}

Изменить: исправлена ​​ошибка.

1
ответ дан 3 December 2019 в 01:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: