Boost C++ Libraries

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

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
Library Documentation Index

Safe Numerics

PrevUpHomeNext

Mixing Data Types Can Create Subtle Errors

C++ contains signed and unsigned integer types. In spite of their names, they function differently which often produces surprising results for some operands. Program errors from this behavior can be exceedingly difficult to find. This has lead to recommendations of various ad hoc "rules" to avoid these problems. It's not always easy to apply these "rules" to existing code without creating even more bugs. Here is a typical example of this problem:

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

#include <iostream>
#include <cstdint>

#include <boost/safe_numerics/safe_integer.hpp>

using namespace std;
using namespace boost::safe_numerics;

void f(const unsigned int & x, const int8_t & y){
    cout << x * y << endl;
}
void safe_f(
    const safe<unsigned int> & x,
    const safe<int8_t> & y
){
    cout << x * y << endl;
}

int main(){
    cout << "example 4: ";
    cout << "mixing types produces surprising results" << endl;
    try {
        std::cout << "Not using safe numerics" << std::endl;
        // problem: mixing types produces surprising results.
        f(100, 100);  // works as expected
        f(100, -100); // wrong result - unnoticed
        cout << "error NOT detected!" << endl;;
    }
    catch(const std::exception & e){
        // never arrive here
        cout << "error detected:" << e.what() << endl;;
    }
    try {
        // solution: use safe types
        std::cout << "Using safe numerics" << std::endl;
        safe_f(100, 100);  // works as expected
        safe_f(100, -100); // throw error
        cout << "error NOT detected!" << endl;;
    }
    catch(const std::exception & e){
        cout << "error detected:" << e.what() << endl;;
    }
    return 0;
}

Here is the output of the above program:

example 4: mixing types produces surprising results
Not using safe numerics
10000
4294957296
error NOT detected!
Using safe numerics
10000
error detected!converted negative value to unsigned: domain error

This solution is simple, just replace instances of int with safe<int>.


PrevUpHomeNext