我目前正在研究C++中的运算符重载,为一个简单的2D顶点类实现[]运算符以获取位置信息。这通常是有效的,但我不知道如何处理错误,例如如果操作符越界(在仅具有x和y值的2D顶点类的情况下,如果它大于1,则越界)。
在这种情况下,处理错误的常见方法是什么?
谢谢。
在这种情况下,处理错误的常见方法是什么?
谢谢。
当你必须抛出异常时,就必须抛出。除非你能返回某种魔法爆炸结果值,否则无法诊断重载运算符中的问题。定义一个异常类型,在出现错误时抛出它,并对其进行文档说明。
operator[]
时出现超出范围错误,我个人会选择第四种选项。并不是因为我特别喜欢看其他程序员在处理我的代码时遇到困难(顺带一提,我确实喜欢,但这与讨论无关),而是因为这是预期的行为。operator[]
时,他们期望自己处理边界检查,并不依赖于类型或类来为他们做任何事情。即使在STL容器中,你也可以看到operator[]
(没有范围检查)与否则多余的object.at()
(进行范围检查)并存。反映出你自己重载运算符的预期行为通常会使代码更加直观。operator[]
用于矩阵或二维数组的实现;而应该使用operator()
。点击这里查看FAQ#13.10
问题在于为多个维度实现[]。operator()
的另一个原因)。我认为加入一个断言可能也是必要的。你是否预见到在二维向量中越界除了(简单?)程序员错误之外还会有其他情况吗?
T& operator[](size_t index)
{
assert(index < 2 && "Vector index out of bounds");
return pos[index];
}
如果你要抛出异常,我想你也可以使用out_of_range或者它的派生类型。
正如其他人所指出的那样,异常是解决问题的方法。
但是,这似乎是访问点类的一种非常不寻常的习惯用语。我认为更直接的方法是让顶点类具有单独的成员:
class Vertex {
...
double x;
double y;
};
vertex1.x - vertex2.x
等操作来对它们进行操作,这在我看来比vertex1[0] - vertex2[0]
更易读。作为额外的奖励,它完全避免了您的异常问题。处理超出边界的索引至少有两种选项,而不是使用异常:
std::terminate()
或直接调用 abort()
等来中止操作,或许在打印错误消息后执行。这两种方法之间有一种折衷方案,即使用 assert
宏。这将在发行版本(使用 NDEBUG 编译)中执行前者,在调试版本中执行后者。
并不是说异常一定是个坏主意,但它们有它们的问题。然而,如果您从不捕获它们,那么大多数问题都会消失。
在这种情况下,调用者必须向您传递0或1。如果他们有时传递2,并计划捕获当它们这样做时发生的异常,则可能没有希望。不要花太多时间担心这个问题。
另一个选择是接受所有输入,但将它们映射到其中一个值。例如,您可以对输入进行按位与运算。这使得您的代码非常简单,但明显的缺点是它会掩盖其他人的错误。
[*] 并不是说专业人士不会犯错。他们也会,只是不指望你来挽救他们的错误。
class ArrayOutOfBounds: public exception{ virtual const char* what() const throw() { return "您要访问的数组越界了!"; } }; T& operator[](uint32 _i){ try{ if(_i>1){ throw exOutOfBounds; } else { return pos[_i]; } } catch (exception& e){ cout << e.what() << endl; exit(0); } }
- moka