Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Library Documentation Index

Safe Numerics


Using safe_range and safe_literal

When trying to avoid arithmetic errors of the above type, programmers will select data types which are wide enough to hold values large enough to be certain that results won't overflow, but are not so large as to make the program needlessly inefficient. In the example below, we presume we know that the values we want to work with fall in the range [-24,82]. So we "know" the program will always result in a correct result. But since we trust no one, and since the program could change and the expressions be replaced with other ones, we'll still use the loose_trap_policy exception policy to verify at compile time that what we "know" to be true is in fact true.

//  Copyright (c) 2018 Robert Ramey
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at

#include <iostream>

#include <boost/safe_numerics/safe_integer_range.hpp>
#include <boost/safe_numerics/safe_integer_literal.hpp>
#include <boost/safe_numerics/exception.hpp>
#include <boost/safe_numerics/native.hpp>
#include "safe_format.hpp" // prints out range and value of any type

using namespace boost::safe_numerics;

// create a type for holding small integers in a specific range
using safe_t = safe_signed_range<
    native,           // C++ type promotion rules work OK for this example
    loose_trap_policy // catch problems at compile time

// create a type to hold one specific value
template<int I>
using const_safe_t = safe_signed_literal<I, native, loose_trap_policy>;

// We "know" that C++ type promotion rules will work such that
// addition will never overflow. If we change the program to break this,
// the usage of the loose_trap_policy promotion policy will prevent compilation.
int main(int, const char *[]){
    std::cout << "example 83:\n";

    constexpr const const_safe_t<10> x;
    std::cout << "x = " << safe_format(x) << std::endl;
    constexpr const const_safe_t<67> y;
    std::cout << "y = " << safe_format(y) << std::endl;
    auto zx = x + y;
    const safe_t z = zx;
    //auto z = x + y;
    std::cout << "x + y = " << safe_format(x + y) << std::endl;
    std::cout << "z = " << safe_format(z) << std::endl;
    return 0;

The output uses a custom output manipulator, safe_format, for safe types to display the underlying type and its range as well as current value. This program produces the following run time output.

example 83:
x = <signed char>[10,10] = 10
y = <signed char>[67,67] = 67
x + y = <int>[77,77] = 77
z = <signed char>[-24,82] = 77

Take note of the various variable types:

All this information regarding the range and values of variables has been determined at compile time. There is no runtime overhead. The usage of safe types does not alter the calculations or results in anyway. So safe_t and const_safe_t could be redefined to int and const int respectively and the program would operate identically - although it might We could compile the program for another machine - as is common when building embedded systems and know (assuming the target machine architecture was the same as our native one) that no erroneous results would ever be produced.