在调用函数之前或之后进行完整性检查吗? [关闭]

问题描述 投票:0回答:2

在性能、代码大小和惯用的 C++ 方面,什么更有意义:将完整性检查留给函数,还是事先进行检查以避免调用函数?

比较以下代码,我在

reserve
insert
中进行了相同的健全性检查。我可以跳过后面直接调用函数。我应该吗?

#include <initializer_list>
#include <cstddef>

struct vector
{
    void insert(std::initializer_list<int> ilist) {
        if (ilist.size() > capacity_) { // ... sanity check here makes sense?
            reserve(ilist.size());
        }
        // ... or just call it regardless?
        // reserve(ilist.size());
        // ...
    }

    void reserve(size_t new_cap) {
        if (new_cap < capacity_) {
            return ;
        }
        // ...
    }
    size_t capacity_;
};

int main()
{
    vector v{6};

    v.reserve(10);
    v.insert({1,2,4,5});
}

我也想用更笼统的术语来讨论这个问题。可能还有我没有考虑到的因素。你会如何处理这种情况?

c++ idioms function-call
2个回答
3
投票

这完全取决于你想提供什么保证。

比较

std::vector

  • 如果您调用
    std::vector::insert
    并且当前容量不足,向量将为新元素腾出空间。
  • 如果您调用
    std::vector::reserve
    时请求的容量小于当前容量,则该函数不执行任何操作。

对于两者,检查不仅仅是“完整性检查”,而且是必需的。

如果你在你的

vector
中删除它们那么你的向量将不同:

  • insert
    假设有足够的容量(这是一个先决条件,如果调用者忽略它,他们会得到他们应得的:未定义的行为)。
  • reserve(x)
    确保调用后的容量正好是
    x
    。如果向量大小大于
    x
    ,它将相应地进行调整。

如果这就是您想要的

vector
,那么支票可以被移除。在发布版本中你不应该做的是检查先决条件。例如,在
operator[]
中进行边界检查,而
operator[]
仅指定用于有效索引。如果调用者忽略前提条件(索引必须有效),那是他们的错。当
operator[]
未明确指定这样做时,遵守前提条件的用户不想为边界检查付费。与具有
std::vector
方法的
at()
进行比较,该方法进行边界检查。

TL;DR:视情况而定。


1
投票

健全性检查用于查明函数开始前的一个或多个参数、函数内部的值以及函数返回值是否有效以继续进行。例如,在访问向量中的元素时考虑边界检查。这种类型的检查被研究为前置条件、断言和后置条件。这种类型的检查通常用于开发时间,通常在生产中关闭。

你在代码中所说的健全性检查实际上是程序逻辑的一部分,你必须这样做。问题是您的支票应该放在哪里? 作为准则,您应该将密切相关的逻辑放在一起。所以你的方法似乎是正确的。

© www.soinside.com 2019 - 2024. All rights reserved.