APr*_*mer 4 c++ overflow numeric-limits
你会如何修复这段代码?
template <typename T> void closed_range(T begin, T end)
{
for (T i = begin; i <= end; ++i) {
// do something
}
}
Run Code Online (Sandbox Code Playgroud)
T被约束为整数类型,可以是更广泛的类型,可以是有符号或无符号的
begin 可 numeric_limits<T>::min()
end可以numeric_limits<T>::max()(在这种情况下++i会溢出上面的代码)
我有几种方式,但我不喜欢.
也许,
template <typename T> void closed_range(T begin, const T end)
if (begin <= end) {
do {
// do something
} while (begin != end && (++begin, true));
}
}
Run Code Online (Sandbox Code Playgroud)
诅咒,我的第一次尝试是错误的,上面的解决方案并不像我希望的那样漂亮.怎么样:
template <typename T> bool advance(T &value) { ++value; return true; }
template <typename T> void closed_range(T first, const T last)
if (first <= last) {
do {
// do something
} while (first != last && advance(first));
}
}
Run Code Online (Sandbox Code Playgroud)
std::advance即使T不是整数类型也没有歧义,因为std::advance它需要2个参数.因此,模板也可以使用例如随机访问迭代器,如果由于某种原因你想要一个封闭的范围.
或者说一下集理论怎么样?显然,如果你只是在一个封闭的范围内编写一个循环,那就太大了,但是如果你想要做很多事情,那么它就会使循环代码正确.不确定效率:在一个非常紧凑的循环中你可能想要确保endof挂起的呼叫:
#include <limits>
#include <iostream>
template <typename T>
struct omega {
T val;
bool isInfinite;
operator T() { return val; }
explicit omega(const T &v) : val(v), isInfinite(false) { }
omega &operator++() {
(val == std::numeric_limits<T>::max()) ? isInfinite = true : ++val;
return *this;
}
};
template <typename T>
bool operator==(const omega<T> &lhs, const omega<T> &rhs) {
if (lhs.isInfinite) return rhs.isInfinite;
return (!rhs.isInfinite) && lhs.val == rhs.val;
}
template <typename T>
bool operator!=(const omega<T> &lhs, const omega<T> &rhs) {
return !(lhs == rhs);
}
template <typename T>
omega<T> endof(T val) {
omega<T> e(val);
return ++e;
}
template <typename T>
void closed_range(T first, T last) {
for (omega<T> i(first); i != endof(last); ++i) {
// do something
std::cout << i << "\n";
}
}
int main() {
closed_range((short)32765, std::numeric_limits<short>::max());
closed_range((unsigned short)65533, std::numeric_limits<unsigned short>::max());
closed_range(1, 0);
}
Run Code Online (Sandbox Code Playgroud)
输出:
32765
32766
32767
65533
65534
65535
Run Code Online (Sandbox Code Playgroud)
在omega<T>对象上使用其他运算符要小心.我只实现了演示的绝对最小值,并omega<T>隐式转换为T,所以你会发现你可以编写表达式,这可能会抛弃omega对象的"无限".你可以通过声明(不一定定义)一整套算术运算符来解决这个问题; 或者如果isInfinite为真,则在转换中抛出异常; 或者只是不要担心它,因为你不能意外地将结果转换回欧米茄,因为构造函数是明确的.但是,例如,omega<int>(2) < endof(2)是真的,但却omega<int>(INT_MAX) < endof(INT_MAX)是错误的.
我的看法:
// Make sure we have at least one iteration
if (begin <= end)
{
for (T i = begin; ; ++i)
{
// do something
// Check at the end *before* incrementing so this won't
// be affected by overflow
if (i == end)
break;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
341 次 |
| 最近记录: |