C++. Сборник рецептов - [57]

Шрифт
Интервал

Смотри также

Рецепт 3.2.

3.6. Преобразования между числовыми типами

Проблема

Имеется число одного типа и требуется преобразовать его в другой, как >int в >short или наоборот, но при этом необходимо перехватывать все ошибки переполнения (overflow) или потери значимости (underflow), возникающие при работе программы.

Решение

Используйте шаблон класса >numeric_cast Boost. Он выполняет проверки, которые при переполнениях переменной, принимающей значение, или других ошибках выбрасывают исключение типа >bad_numeric_cast. Пример 3.8 показывает, как это выполняется.

Пример 3.8. Безопасное преобразование чисел

>#include

>#include


>using namespace std;

>using boost::numeric_cast;

>using boost::bad_numeric_cast;


>int main() {

> // Целые типы

> try {

>  int i = 32767;

>  short s = numeric_cast(i);

>  cout << "s = " << s << endl;

>  i++; // Теперь i выходит за диапазон (если sizeof(short) равен 2)

>  s = numeric__cast(i);

> } catch (bad_numeric_cast& e) {

>  cerr << e.what() << endl;

> }

> try {

>  int i = 300;

>  unsigned int ui = numeric_cast(i);

>  cout << ui << endl; // Прекрасно

>  i *= -1;

>  ui = numeric_cast(i); // i отрицателен!

> } catch (bad_numeric_cast& e) {

>  cerr << e.what() << endl;

> }

> try {

>  double d = 3.14.

>  int i = numeric_cast(d);

>  i = numeric_cast(d); // Это отрезает 0.14!

>  cout << i << endl; // i = 3

> } catch (bad_numeric_cast& e) {

>  cerr << e.what( ) << endl;

> }

>}

Обсуждение

Вы, вероятно, знаете, что базовые типы C++ имеют различные размеры. Стандарт C++ содержит жесткие указания по относительному размеру типов: >int всегда не короче, чем >short int, но он не указывает абсолютных размеров. Это означает, что если взять >long int и попытаться записать его значение в >short или попытаться поместить >int в >unsigned int, то информация о значении переменной-источника, такая как знак или даже часть числового значения, может быть потеряна.

Только знания, что это может привести к проблемам, не достаточно. Вы можете быть ограничены жесткими требованиями по объему и не захотите использовать четыре байта для >long, когда можно обойтись двумя байтами для >short (если ваша платформа на самом деле использует такие размеры, что очень распространено, но не гарантируется). Из-за ограничений по объему может возникнуть желание попробовать хранить значения в наименьших возможных типах. Если вы любите приключения, но вам нужна страховка, для перехвата потерь данных при работе программы используйте >numeric_cast из Boost.

Синтаксис >numeric_cast очень прост. Это шаблон функции, объявленный следующим образом.

>template

>inline Target numeric_cast(Source arg)

Если вы уже прочли рецепты 3.1 и 3.3, он аналогичен >lexical_cast. У него имеется два параметра шаблона — >Target и >Source, — которые представляют типы оригинального и результирующего значений. Так как это шаблон функции, компилятор может догадаться о типе аргумента >Source, так что требуется указать только >Target, как здесь.

>int i = 32767;

>short s = numeric_cast(i);

>short — это аргумент, передаваемый в шаблон как параметр >Target. Компилятор догадывается, что >Source имеет тип >int потому, что >i имеет тип >int.

В этом случае я впихиваю >int в >short. В моей системе (Windows XP) int имеет длину четыре байта, a >short — два. >short имеет знак, это означает, что для представления числа в нем используется 15 бит и, следовательно, максимальным допустимым положительным значением для него является 32 767. Приведенный выше фрагмент кода работает молча, но когда я увеличиваю >i на единицу, она выходит за диапазон >short.

>s = numeric_cast(i); // Ох!

Вы уже догадались, что выбрасывается исключение >bad_numeric_cast. Смотри остальную часть примера 3.8: >numeric_cast также перехватывает потери знака, возникающие при присвоении отрицательного значения со знаком типу без знака.

Но >numeric_cast не решает всех проблем. Если попытаться поместить значение с плавающей точкой в тип без плавающей точки, то будет потеряно все, что находится справа от десятичной точки, так? >numeric_cast в этой ситуации не спасает, так что не думайте, что он сможет уберечь вас от всех рискованных предприятий. Например, рассмотрим такой фрагмент кода из примера 3.8:

>double a = 3.14;

>int i = numeric_cast(d); // Ох!

Здесь не будет выброшено никаких исключений. Но это произойдет, если попробовать такое:

>double d = -3.14;

>unsigned int ui = numeric_cast(d);

Потому что, несмотря на то что происходит потеря всего, что находится справа от десятичной точки, происходит потеря знака, а это очень плохо.

Смотри также

Рецепты 3.1 и 3.3.

3.7. Получение минимального и максимального значений числового типа

Проблема

Требуется узнать наибольшее и наименьшее значения, представляемые на данной платформе числовым типом, таким как >int или >double.

Решение

Чтобы среди прочего получить максимальное и минимальное допустимые значения числового типа, используйте шаблон класса >numeric_limits из заголовочного файла > (см. пример 3.9).

Пример 3.9. Получение числовых ограничений

>#include

>#include


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет собой уникальное учебное и справочное пособие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий Delphi».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.