Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.189.2.122] |
|
Сообщ.
#1
,
|
|
|
Есть преобразование:
vector<...> V; int N=V.size(); вот тут надо произвести преобразование типов так, чтобы не было переполнения. Смотрел static_cast, dynamic_cast и reinterpret_cast, но что-то не понятно. Пробовал так: int &N=dynamic_cast<int&>(V.size()); Транслятор выдает ошибку. Как правильно написать преобразование, чтобы на этапе выполнения не возникала ошибка, и можно было бы отследить невозможное преобразование исключительной ситуацией? |
Сообщ.
#2
,
|
|
|
Из коробки никак, только написать свою функцию, которая проверяет диапазон и кидает исключение, если что не так.
|
Сообщ.
#3
,
|
|
|
А почему сразу не использовать size_t?
|
Сообщ.
#4
,
|
|
|
Цитата OpenGL @ Из коробки никак, только написать свою функцию, которая проверяет диапазон и кидает исключение, если что не так. Написал функцию, но проблема переполнения числового типа в С++ не решена. В Delphi в свойствах проекта есть возможность включить контроль переполнения переменных числового типа. Существует ли такая возможность в С++? |
Сообщ.
#5
,
|
|
|
Цитата a_n_y_a @ Существует ли такая возможность в С++? if (value > std::numeric_limits<int>::max()) { } |
Сообщ.
#6
,
|
|
|
Цитата a_n_y_a @ Нет, если только конкретная среда разработки (Visual Studio, например, но я не проверял, как оно там) подобной фичи не предлагает.Существует ли такая возможность в С++? В общем случае это проблематично, ибо пользователь вправе создавать собственные типы данных с нестандартными свойствами. Какие-нибудь длинные целые, например, или очень сильно расширенные вещественные. Та даже std::complex уже создаст проблемы. Можно попробовать самому научить этому компилятор, хотя бы для стандартных типов. Типа этого: template <typename T, typename U> struct SafeCast { static T doIt(const U& val) { using common_type = std::common_type_t<T, U>; constexpr common_type high= std::min(static_cast<common_type>(std::numeric_limits<T>::max()), static_cast<common_type>(std::numeric_limits<U>::max())), low = std::is_signed_v<T> == std::is_signed_v<U> ? std::max(static_cast<common_type>(std::numeric_limits<T>::min()), static_cast<common_type>(std::numeric_limits<U>::min())) : 0; if (val > high || val < low) throw std::runtime_error("Value exceeds allowed bounds."); return static_cast<T>(val); } }; /* Безопасный к переполнению каст арифметических типов. */ template <typename T, typename U> inline T safe_cast(const U& val) { return SafeCast<T, U>::doIt(val); } /* ... */ std::vector<some_type> V(some_size); /* ... */ int N = safe_cast<int>(V.size()); |
Сообщ.
#7
,
|
|
|
Хорошая идея, но вот этого я не понял:
int N = safe_cast<int>(V.size()); Далее мы работаем с тем же int? Переменная N будет наращиваться, например N++; И при этом результат наращивания не контролируется? При этом возможно переполнение! |
Сообщ.
#8
,
|
|
|
Конкретно тут если, то зачем ей наращиваться-то? Размер вектора от этого не изменится, а если изменится, то его снова надо брать от самого вектора.
А в целом, в коде всё есть, что может оказаться нужным: как получить общий тип, как обработать разную знаковость, как проконтролировать диапазон результата. На его основе накидать какой-нибудь template <typename T> class Checked; можно несложно. И использовать потом Checked<int>, например, вместо сырого int. В арифметических операциях можно либо заранее проверять диапазон результата для самого широкого типа, либо выполнять операции над более широким типом с последующим кастом. При смешении типов делать то же, но над common_type аргументов с учётом разной знаковости. Метакод выйдет несложный. С указателями и ссылками на Checked<> могут возникнуть сложности при смешении своего и стороннего кода, но и в Delphi возникли бы похожие сложности, если готовые модули брать. |
Сообщ.
#9
,
|
|
|
Кстати, вспомнил тут. Посмотри в boost::multiprecision. Основное назначение – неограниченная разрядная сетка и точность, однако в качестве бонуса есть и контроль диапазонов.
|