7

在用 C++ 编写科学软件多年后,我似乎仍然无法习惯异常,也不知道什么时候应该使用它们。我知道使用它们来控制程序流是一个很大的禁忌,但除此之外......考虑以下示例(摘自表示图像蒙版并让用户将区域添加为多边形的类):

class ImageMask
{
public:
    ImageMask() {}
    ImageMask(const Size2DI &imgSize);

    void addPolygon(const PolygonI &polygon);

protected:
    Size2DI imgSize_;
    std::vector<PolygonI> polygons_;
};

此类的默认构造函数创建一个无用的实例,具有未定义的图像大小。我不希望用户能够将多边形添加到这样的对象。但我不确定如何处理这种情况。当大小未定义并调用 addPolygon() 时,我应该:

  1. 默默归来,
  2. assert(imgSize_.valid) 使用此类检测代码中的违规行为并在发布前修复它们,
  3. 抛出异常?

大多数情况下,我选择 1) 或 2)(取决于我的心情),因为在我看来,对于这样一个简单的场景来说,例外是昂贵的、混乱的并且简直是矫枉过正。请问有什么见解吗?

4

4 回答 4

6

一般规则是当您无法执行所需的操作时抛出异常。因此,在您的情况下,是的,当调用 addPolygon 并且大小未定义或不一致时抛出异常确实有意义。

默默地回来几乎总是错误的事情。assert不是一种好的错误处理技术(它更像是一种设计/文档技术)。

但是,在您的情况下,重新设计界面以使错误条件不可能或不可能发生可能会更好。例如,像这样:

class ImageMask
{
public:
    // Constructor requires collection of polygons and size.
    // Neither can be changed after construction.
    ImageMask(std::vector<PolygonI>& polygons, size_t size);
}

或者像这样

class ImageMask
{
public:
    class Builder
    {
    public:
        Builder();
        void addPolygon();
    };

    ImageMask(const Builder& builder);
}

// used like this
ImageMask::Builder builder;
builder.addPolygon(polyA);
builder.addPolygon(polyB);
ImageMask mask(builder);
于 2012-07-13T13:15:46.477 回答
2

我会尽量避免任何可能创建处于某种无用状态的数据的情况。如果您需要一个不为空的多边形,那么不要创建空多边形,这样可以省去很多麻烦,因为编译器会强制要求没有空多边形。

我从不使用静默返回,因为它们隐藏了错误,这使得查找错误比必须的要复杂得多。

当我检测到程序处于它只能处于的状态时,我会使用断言,如果软件中存在错误的话。在您的示例中,如果您签入采用 Size2DI 的 c'tor,则该大小不为空,而不是断言存储的大小不为空,这对于检测错误很有用。断言不应该有副作用,并且必须可以在不改变软件行为的情况下删除它们。我发现它们非常有用,可以找到我自己的错误并记录对象/函数的当前状态等。

如果很有可能运行时错误将由函数的调用者直接处理,我会使用常规的返回值。如果很有可能,这种错误情况必须通过调用堆栈上的多个函数调用来传达,我更喜欢异常。有疑问我提供两个功能。

亲切的问候托尔斯滕

于 2012-07-13T13:28:31.313 回答
1

对我来说,1 是没有选择的。是 2 还是 3 取决于您的程序/库的设计,您是否考虑(和记录)默认构造图像掩码,然后添加多边形是组件的有效或无效使用。这是一个重要的设计决策。我推荐阅读Matthew Wilson 的这篇文章

请注意,您有更多选择:

  • 发明自己的断言,始终调用 std::terminate 并进行额外的日志记录
  • 禁用默认构造函数(正如其他人已经指出的那样)——这是我最喜欢的
于 2012-07-13T13:22:10.223 回答
1
  1. “悄悄回来”——这是真正的“大禁忌”。程序应该知道出了什么问题。
  2. "assert" - 第二条规则是仅当正常程序的流程无法恢复时才使用断言。
  3. “抛出异常” - 是的,这是正确且良好的技术。只需注意异常安全。GotW上有很多关于异常安全编码的文章。

不要害怕例外。他们不咬人。:) 如果您能充分掌握这项技术,您将成为一名出色的编码员。;)

于 2012-07-13T13:30:36.227 回答