在C或C ++中检查边界是否昂贵?

绑定检查很昂贵(>运行时开销的x2倍)

我从我的一位教授那里得到了这一点。 我很困惑。 据我所知,程序中最耗时的部分是IO(来自网络和硬盘)。

但是用C或C ++检查边界并不总是与那两个输入源相关。 例如,我使用memcpy(dest, src, length(src))在C中将一个buff的内容复制到另一个buff。 在此之前,我检查src的大小,以防止堆溢出。 我可以成像的进程是:获取src的起始地址和src\x00字节(在汇编语言的视图中,我逐个复制src的内容,看看该字节是否与\x00等效)。 获得2地址后,只需减去它们以获得src的长度。 我从内存中读取了src的内容。 我们都知道从记忆中读取东西很快。

我刚刚运行了一个程序,启用了迭代器边界检查。

运行时间从789毫秒增加到2608毫秒。

所以,是的,这很重要。 不是所有的时间,但肯定比从来没有。

特别是,绑定检查的迭代器需要至少两倍于简单指针的存储空间,而且,不容易优化。 从理论上讲,它们既简单又有效,但实际上你根本不想做你不需要的工作。

哦,我提到编译时间从7.72秒到13.21秒也是如此?


对于你们中间的许多非信徒来说……一个微型例子需要0.92秒而没有边界检查,而且需要1.96秒 。


因为对所有事情都抱有很多怀疑,包括vector的效率……这是另一个:

 #include  #include  template struct Vector { T *b, *e; Vector(size_t n) : b(new T[n]), e(b + n) { } T &operator[](size_t i) { return b[i]; } T &at(size_t i) { if (i >= e - b) { throw "invalid"; } return b[i]; } }; #define at operator[] // Comment this out to enable bounds-checking int main(int argc, char **argv) { Vector v(1 << 16); for (size_t *p = vb; p != ve; ++p) { *p = 1; } clock_t begin = clock(); for (int j = 0; j < 1 << 12; ++j) { for (size_t i = 8, n = ve - vb; i < n; ++i) { v.at(i) += v.at(i - 8); v.at(i) ^= v.at(i - 7); v.at(i) -= v.at(i - 6); v.at(i) ^= v.at(i - 5); v.at(i) += v.at(i - 4); v.at(i) ^= v.at(i - 3); v.at(i) -= v.at(i - 2); v.at(i) ^= v.at(i - 1); } } clock_t end = clock(); fprintf(stderr, "%u\n", clock() - begin); } 

2.09秒对0.88秒 。

这曾经是直到20世纪80年代才是真实的。

利用现代代码生成和高度流水线的CPU架构,可以在零或非常少的额外执行成本的情况下完成边界检查。 这是因为边界检查可以与内存提取并行进行。