c ++:运算符重载和错误处理

时间:2009-12-05 18:48:32

标签: c++ error-handling operator-overloading

我目前正在开始研究c ++中的运算符重载,以获得一个简单的2D顶点类,其中位置应该可以通过[]运算符使用。这通常有效,但我真的不知道如何处理错误,例如如果运算符超出界限(在2D顶点类只有x和y值的情况下,如果它大于一个)

在这种情况下处理错误的常用方法是什么?

由于

6 个答案:

答案 0 :(得分:4)

如果必须throw,则必须throw。除非您可以返回某种魔法爆炸结果值,否则没有其他方法可以诊断重载运算符中的问题。定义一个异常类型,抛出错误,记录它。

答案 1 :(得分:2)

根据C ++语言常见问题解答,operator[]应该用于矩阵或二维数组实现;而是使用operator()Click here for FAQ #13.10

最大的问题是为多个维度实施[]。

对于错误,如果您不想为重载运算符提供任何额外参数,则必须转到 exception 路由(使用operator()的另一个原因。 / p>

答案 2 :(得分:2)

错误处理在最好的时候是一个棘手的野兽。它几乎可以归结为错误有多大,以及如果发生错误会发生什么事情。

您可以遵循四种基本路径:

  1. 抛出异常
    • 错误处理的大锤。一个很棒的工具,如果你需要它肯定想用它,但是如果你不小心你最终会把自己砸在脚下。
    • 基本上跳过throwcatch之间的所有内容,除了死亡和毁灭之外别无他物。
    • 如果没有被抓住,它将中止你的程序。
  2. 返回表示失败的值
    • 留给程序员检查是否成功并作出相应的反应。
    • 失败值取决于类型。指针可以返回NULL0,STL容器返回object.end(),否则可以使用未使用的值(例如-1"")。
  3. 优雅地处理条件
    • 有时,错误不是真正的错误,只是给您带来不便。
    • 如果仍然可以提供有用的结果,可以在地毯下轻易扫除错误而不会伤害任何人。
    • 例如,超出范围的错误只能返回数组中的最后一个变量,而不需要诉诸任何混乱的异常内容。
    • 只要可预测定义,程序员就可以按照自己的意愿制作它。
  4. 未定义的行为
    • 嘿,程序员不应该首先给你不好的输入。让他们受苦。
  5. 一般情况下,我只会选择一个选项,因为那些破解程序的东西,对于我没有真正期望在没有协同努力的情况下恢复的东西。否则,使用异常作为流量控制的形式比回到goto的日子好一点。

    选项二可能是非破解程序错误最常见的,但它的有效性实际上取决于您正在处理的返回类型。这是有利的,因为它允许程序员通过检测故障和恢复自身来本地控制流。在处理重载运算符时,它的用途有限,但我认为为了完整起见我会把它丢弃。

    选项三非常特定于环境。许多错误无法以这种方式处理,甚至是那些可能导致不直观结果的错误。请谨慎使用,并确保彻底记录。或者,根本不记录,并假装它是选项四。


    现在,至于提供的具体示例,即在重载operator[]上超出范围错误,我个人会选择四。并不是因为我特别喜欢看到其他程序员在处理我的代码时遭受的损失(顺便说一句,但这与讨论相关),但是因为它是预期的。

    程序员使用operator[]的大多数情况下,他们希望处理自己的边界检查,而不依赖于类型或类来为它们做任何事情。即使在STL容器中,您也可以看到operator[](无范围检查)与其他冗余object.at()进行范围检查)并行查看。使用自己的重载运算符来反映预期的行为往往会产生更直观的代码。

答案 3 :(得分:1)

我认为断言也可能存在。你是否预见到在2d向量中超出(简单?)程序员的错误会不会是其他任何东西?

T& operator[](size_t index)
{
    assert(index < 2 && "Vector index out of bounds");
    return pos[index];
}

如果您要抛出异常,我想您也可以使用out_of_range - 或从中派生的类型。

答案 4 :(得分:1)

正如其他人所指出的那样,例外是可行的方法。

但对于访问像这样的点类来说,这似乎是一个非常不寻常的习惯用语。我会发现顶点类有单独的成员更直接:

class Vertex {
    ...
    double x;
    double y;
};

然后你可以通过vertex1.x - vertex2.x等操作来操作它们,IMO比vertex1[0] - vertex2[0]更具可读性。为了获得额外的奖励,它可以完全避免您的异常问题。

答案 5 :(得分:1)

除了处理超出范围的索引的异常之外,您至少有两个选项:

  • 只需信任您的输入,记录未定义的行为即可使用索引超出范围,并依赖您的呼叫者成为专业人士[*]。
  • 如果索引超出范围,可以通过直接调用std::terminate()abort()或其他任何内容(可能在打印错误消息后)中止。

两者之间存在折衷,即使用assert宏。这将在发布版本(使用NDEBUG编译)中执行前者,后者在调试版本中执行。

不是说异常一定是个坏主意,但他们有问题。然后,如果你从来没有抓住它们,大多数问题都会消失。

在这种情况下,调用者必须向你传递0或1.如果他们有时会传递给你2,并计划捕获他们这样做时发生的异常,那么他们可能没有希望。不要花太多时间担心它。

另一种选择是接受所有输入,但将它们映射到一个或另一个值。例如,您可以按位 - 并且输入为1.这使您的代码非常简单,明显的缺点是它会掩盖其他人的错误。

[*]并不是说专业人士不犯错误。他们是这样。他们只是不指望你将他们从错误中解救出来。