我什么时候必须检查整数溢出?

When do I have to check for integer overflow?

我一直在研究整数溢出,最后创建了一个检查整数溢出和下溢的函数:

#include <exception>
#include <limits>

int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        throw std::exception("Integer overflow");
    } else if (a < 0 && b < INT_MIN - a) {
        throw std::exception("Integer underflow");
    }
    return a + b;
}

我害怕可能出现的性能问题,所以我做了下一个基准测试:

#include <iostream>
#include <exception>
#include <limits>
#include <chrono>
#include <string>

int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        throw std::exception("Integer overflow");
    } else if (a < 0 && b < INT_MIN - a) {
        throw std::exception("Integer underflow");
    }
    return a + b;
}

void bench_add() {
    for (int i = INT16_MIN; i < INT16_MAX; i++) {
        for (int j = INT16_MIN; j < INT16_MAX; j++) {
            volatile int x = i + j; //I make it volatile so the compiler doesn't optimize it out
        }
    }
}

void bench_safe_add() {
    for (int i = INT16_MIN; i < INT16_MAX; i++) {
        for (int j = INT16_MIN; j < INT16_MAX; j++) {
            volatile int x = safe_add(i, j); //I make it volatile so the compiler doesn't optimize it out
        }
    }
}

void bench_safe_add_with_try() {
    try {
        for (int i = INT16_MIN; i < INT16_MAX; i++) {
            for (int j = INT16_MIN; j < INT16_MAX; j++) {
                volatile int x = safe_add(i, j); //I make it volatile so the compiler doesn't optimize it out
            }
        }
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}

void chrono(const std::string& name, void function(void)) {
    using namespace std::chrono;
    milliseconds start = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
    function();
    long long time = (duration_cast<milliseconds>(system_clock::now().time_since_epoch()) - start).count();
    std::cout << name << ": " << time << "ms" << std::endl;
}

int main() {
    chrono("Standard add", bench_add);
    chrono("Safe add", bench_safe_add);
    chrono("Safe add surrounded by try block", bench_safe_add_with_try);
    system("PAUSE");
    return 0;
}

在我的机器(i7-6700K@4GHZ 16gb RAM)中产生这个输出:

Standard add: 1341ms
Safe add: 13667ms
Safe add surrounded by try block: 13544ms

如果我首先使用 try 块调用函数,那么安全添加时间会大大缩短。也许用于分支预测?

重点是safe_add好像比简单的加法慢很多,那么什么时候检查整数溢出呢?或者我什么时候应该 NOT 检查整数溢出?每次用户输入都使用它很重要还是程序应该崩溃?当领先的数据库因为需要另一个查询而对性能产生更大影响时?

谢谢你,佩德罗。

@nikitoz 已经给出了我想要的答案:

You never need to check for integer overflow. Validate user input against some sanity real-world checks, use long long type if you expect big integers, use special class for very big integers of whatever size if you really need that (usually not). program will not crash because of integer overflow.

所以我会将其标记为已回答