Die Boost C++ Bibliotheken

Kapitel 61. Boost.NumericConversion

Die Bibliothek Boost.NumericConversion kann eingesetzt werden, wenn Zahlen eines nummerischen Typs in Zahlen eines anderen nummerischen Typs umgewandelt werden sollen. Derartiges kann in C++ auch implizit geschehen, wie im Beispiel 61.1 zu sehen.

Beispiel 61.1. Implizite Konvertierung von int zu short
#include <iostream>

int main()
{
  int i = 0x10000;
  short s = i;
  std::cout << s << '\n';
}

Das Beispielprogramm wird ohne Fehler kompiliert, weil die Umwandlung von int zu short in C++ automatisch erfolgt. Obwohl es keinen Compilerfehler gibt und das Programm ausgeführt werden kann, kann das Ergebnis der Umwandlung nicht vorhergesagt werden. Das Problem ist, dass die Zahl 0x10000 in der Variablen i zu groß ist, um in einer short-Variablen gespeichert werden zu können. Das Ergebnis ist abhängig von der Implementation. So gibt Beispiel 61.1 mit Visual C++ 2013 kompiliert 0 aus. Der Zahlenwert in s unterscheidet sich demnach deutlich von dem in i.

Um sicherzustellen, dass es bei einer Umwandlung von Zahlen zu keinen derartigen Fehlern kommt, kann der Cast-Operator boost::numeric_cast eingesetzt werden.

Beispiel 61.2. Überläufe entdecken mit boost::numeric_cast
#include <boost/numeric/conversion/cast.hpp>
#include <iostream>

int main()
{
  try
  {
    int i = 0x10000;
    short s = boost::numeric_cast<short>(i);
    std::cout << s << '\n';
  }
  catch (boost::numeric::bad_numeric_cast &e)
  {
    std::cerr << e.what() << '\n';
  }
}

boost::numeric_cast wird genauso angewandt wie die aus C++ bekannten Cast-Operatoren. Dazu muss lediglich die entsprechende Headerdatei eingebunden werden, die in diesem Fall boost/numeric/conversion/cast.hpp heißt.

boost::numeric_cast führt die gleiche Umwandlung von Zahlen unterschiedlicher nummerischer Typen aus, wie es in C++ auch ohne Cast-Operator implizit geschieht. Der Unterschied ist, dass boost::numeric_cast überprüft, ob die Umwandlung einer Zahl so ausgeführt werden kann, dass das Ergebnis gleich dem Ausgangswert ist. Für Beispiel 61.2 bedeutet dies, dass keine Umwandlung durchgeführt wird. Stattdessen wird eine Ausnahme vom Typ boost::numeric::bad_numeric_cast geworfen, weil 0x10000 zu groß ist, um in einer short-Variable gespeichert werden zu können.

Genaugenommen wird keine Ausnahme vom Typ boost::numeric::bad_numeric_cast geworfen, sondern vom Typ boost::numeric::positive_overflow. Dieser Ausnahmetyp beschreibt einen sogenannten Überlauf – in diesem Fall für positive Zahlen. So gibt es auch eine Klasse boost::numeric::negative_overflow, die einen Überlauf für negative Zahlen beschreibt. Sehen Sie sich dazu Beispiel 61.3 an.

Beispiel 61.3. Überlauf für negative Zahlen
#include <boost/numeric/conversion/cast.hpp>
#include <iostream>

int main()
{
  try
  {
    int i = -0x10000;
    short s = boost::numeric_cast<short>(i);
    std::cout << s << '\n';
  }
  catch (boost::numeric::negative_overflow &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Boost.NumericConversion definiert weitere Ausnahmetypen. Da alle von boost::numeric::bad_numeric_cast abgeleitet sind, können sie alle mit dieser Klasse abgefangen werden. Da boost::numeric::bad_numeric_cast seinerseits von std::bad_cast abgeleitet ist, könnte ein catch-Handler auch Ausnahmen dieses Typs abfangen.