原因
代码的清晰度和性能:
- 你无需为在编译时捕获的错误编写错误处理程序==》代码结构清晰、简洁
- 编译时检查不会占用执行时间==》性能更好
例子
// Int is an alias used for integers
int bits = 0; // don't: avoidable code
for(Int i = 0; i ; i <<= 1){
++bits;
}
if(bits < 32){
cerr << "Int too small";
}
这个例子无法达成它想要达成的目标(因为溢出时的行为是无定义的),应该使用static_assert
代替
- 代码目的:通过一个循环的左移操作计算Int的位数,如果小于32为就报错。这是一种运行时检查方式
static_assert
支持编译时的断言错误
// Int is an alias used for integers
static_assert(sizeof(Int) >= 4); // do: compile-time check
更好的做法是只使用类型系统并替换Int
为int32_t
例子:
void read(int* p, int n); // 将最大n个整数读入*p
int a[100];
read(a, 1000); // bad, off the end
better:
void read(span<int> r); // 读入整数r的范围
int a[100];
read(a); // better: 让编译器计算出元素的数量
注:
- 使用指针传递数据的read可以使用int型的大小信息进行范围检查,但是这种检查只能在执行时进行
- span包含了数组的尺寸信息,如果数组长度在编译时就可以确定,span就可以实现编译时范围检查。
通过指针传递数据之后,大小信息也作为变量传递,因此之后的范围检查都只能在执行时进行。有了模板类span之后,这些检查都可以重新考虑,看看是否能够变成编译时检查
建议
- 注意指针类型参数
- 注意运行时对范围违反的检查
也就是说:编译时能做的,就不要延迟到运行时