gaa*_*kam 6 c++ integer-overflow
如标题中所示.作为练习,我想创建一个int来强制对其值进行约束,并且不允许将其设置为超出其指定范围的值.
以下是我尝试解决此问题的方法:
#include <cassert>
#include <cstdint>
#include <iostream>
using namespace std;
int main();
template<typename valtype, valtype minval, valtype maxval>
class ConstrainedValue
{
valtype val;
static bool checkval (valtype val)
{
return minval <= val && val <= maxval;
}
public:
ConstrainedValue() : val{minval} // so that we're able to write ConstrainedValue i;
{
assert(checkval(val));
}
ConstrainedValue(valtype val) : val{val}
{
assert(checkval(val));
}
ConstrainedValue &operator = (valtype val)
{
assert(checkval(val));
this->val = val;
return *this;
}
operator const valtype&() // Not needed here but can be; safe since it returns a const reference
{
return val;
}
friend ostream &operator << (ostream& out, const ConstrainedValue& v) // Needed because otherwise if valtype is char the output could be bad
{
out << +v.val;
return out;
}
friend istream &operator >> (istream& in, ConstrainedValue& v) // this is horrible ugly; I'd love to know how to do it better
{
valtype hlp;
auto hlp2 = +hlp;
in >> hlp2;
assert(checkval(hlp2));
v.val = hlp2;
return in;
}
};
int main()
{
typedef ConstrainedValue<uint_least8_t, 0, 100> ConstrainedInt;
ConstrainedInt i;
cin >> i;
cout << i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
问题是......这不起作用.如果给定此自定义整数的值超出其基础类型,则只会设置错误的值.
例如,假设我们的范围约束为[0; 100],底层类型是uint_least8_t,如上例所示.uint_least8_t计算为char或unsigned char,我不确定是哪一个.让我们尝试用不同的值来提供这个程序:
10
10
Run Code Online (Sandbox Code Playgroud)
尼斯.作品.
101
test: test.cpp:52: std::istream& operator>>(std::istream&, ConstrainedValue<unsigned int, 0u, 100u>&): Assertion `checkval(hlp2)' failed.
Aborted
Run Code Online (Sandbox Code Playgroud)
哈哈!正是我想要的.
但:
257
1
Run Code Online (Sandbox Code Playgroud)
是啊.溢出,截断,错误值,无法正确检查范围.
如何解决这个问题?
我认为不可能在进入构造函数的过程中检测到溢出,因为它是为了满足构造函数参数而执行的,所以一旦它到达构造函数主体,它就已经溢出了。
一种可能的解决方法是在界面中接受大类型,然后进行检查。例如,您可以long int在界面中采用 s,然后将它们在内部存储为valtype. 由于无论如何您都会执行边界检查,因此它应该相当安全。