На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Преобразовать тип size_t в тип int , В процессе выполнения программы возникает необходимость в таком преобразовании
    Есть преобразование:

    ExpandedWrap disabled
      vector<...> V;
      int N=V.size(); вот тут надо произвести преобразование типов так, чтобы не было переполнения.


    Смотрел static_cast, dynamic_cast и reinterpret_cast, но что-то не понятно. Пробовал так:
    ExpandedWrap disabled
       int  &N=dynamic_cast<int&>(V.size());

    Транслятор выдает ошибку. Как правильно написать преобразование, чтобы на этапе выполнения не возникала ошибка, и можно было бы отследить невозможное преобразование исключительной ситуацией?
      Из коробки никак, только написать свою функцию, которая проверяет диапазон и кидает исключение, если что не так.
        А почему сразу не использовать size_t?
          Цитата OpenGL @
          Из коробки никак, только написать свою функцию, которая проверяет диапазон и кидает исключение, если что не так.

          Написал функцию, но проблема переполнения числового типа в С++ не решена. В Delphi в свойствах проекта есть возможность включить контроль переполнения переменных числового типа. Существует ли такая возможность в С++?
            Цитата a_n_y_a @
            Существует ли такая возможность в С++?

            ExpandedWrap disabled
              if (value > std::numeric_limits<int>::max())
              {
               
              }
              Цитата a_n_y_a @
              Существует ли такая возможность в С++?
              Нет, если только конкретная среда разработки (Visual Studio, например, но я не проверял, как оно там) подобной фичи не предлагает.
              В общем случае это проблематично, ибо пользователь вправе создавать собственные типы данных с нестандартными свойствами. Какие-нибудь длинные целые, например, или очень сильно расширенные вещественные. Та даже std::complex уже создаст проблемы. Можно попробовать самому научить этому компилятор, хотя бы для стандартных типов. Типа этого:
              ExpandedWrap disabled
                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());
              Сообщение отредактировано: Qraizer -
                Хорошая идея, но вот этого я не понял:

                ExpandedWrap disabled
                  int N = safe_cast<int>(V.size());



                Далее мы работаем с тем же int? Переменная N будет наращиваться, например N++; И при этом результат наращивания не контролируется? При этом возможно переполнение!
                  Конкретно тут если, то зачем ей наращиваться-то? Размер вектора от этого не изменится, а если изменится, то его снова надо брать от самого вектора.
                  А в целом, в коде всё есть, что может оказаться нужным: как получить общий тип, как обработать разную знаковость, как проконтролировать диапазон результата. На его основе накидать какой-нибудь template <typename T> class Checked; можно несложно. И использовать потом Checked<int>, например, вместо сырого int. В арифметических операциях можно либо заранее проверять диапазон результата для самого широкого типа, либо выполнять операции над более широким типом с последующим кастом. При смешении типов делать то же, но над common_type аргументов с учётом разной знаковости. Метакод выйдет несложный. С указателями и ссылками на Checked<> могут возникнуть сложности при смешении своего и стороннего кода, но и в Delphi возникли бы похожие сложности, если готовые модули брать.
                    Кстати, вспомнил тут. Посмотри в boost::multiprecision. Основное назначение – неограниченная разрядная сетка и точность, однако в качестве бонуса есть и контроль диапазонов.
                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                    0 пользователей:


                    Рейтинг@Mail.ru
                    [ Script execution time: 0,0275 ]   [ 16 queries used ]   [ Generated: 16.04.24, 21:03 GMT ]