22 December 2021

C++ 核心指南目录

P.5 Prefer compile-time checking to run-time checking

理由

能在编译时检查出错误,就不要在运行时检查,这样可以不用编写错误处理代码。代码的可读性会更好、性能会更佳。

例子

以下代码在运行时检查 int 类型的长度是不是小于 32 位:

int bits = 0;         // don't: avoidable code
for (int i = 1; i; i <<= 1)
    ++bits;
if (bits < 32)
    cout << "int too small\n";
cout << bits;
32

因为数值溢出的行为是未定义的,因此以上实现是不可靠的。可以用 static_assert 进行判断:

static_assert(sizeof(int) >= 4);    // do: compile-time check

如果改成 >=8静态判断就出错了:

static_assert(sizeof(int) >= 8);    // do: compile-time check
C-src-99WMqo.cpp:11:27: error: static assertion failed
   11 | static_assert(sizeof(int) >= 8);    // do: compile-time check
      |               ~~~~~~~~~~~~^~~~

更好的做法是使用int32_t类型。

cout << sizeof(int32_t);
4

例子

如果传递给 read 函数的第二个参数过大的话,就会导致数组越界访问:

void read(int* p, int n);   // read max n integers into *p

int a[100];
read(a, 1000);    // bad, off the end

如果使用了gsl::span,编译器就能指导一次读取能放多少数据到数组了:

void read(gsl::span<int> r); // read into the range of integers r

int a[100];
read(a);        // better: let the compiler figure out the number of elements

其他

不要把能在编译时检查的动作延后到运行时。

强化

  • 检查指针参数
  • 检查运行时进行范围越界检测的代码