static不能乱用


我以前只知道 static 关键字可以让变量读取变快,但是实际上对 static 的滥用会导致极为严重的后果。

我们来看一个案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//读入失败返回true
template <class T> bool read(T &r) {
r = 0; static char ch = getchar(); static bool f = false;
while (ch < 48 || ch > 57) { if (ch == EOF) return true; if (ch == 45) f ^= 1; ch = getchar(); }
while (ch >= 48 && ch <= 57) { r = r * 10 + ch - 48; ch = getchar(); }
if (f) r = -r; return false;
}
template <class T> void write(T w, char end = '\n') {
static char write_buf[55], *pos = write_buf;
if (w == 0) { putchar('0'); putchar(end); return; }
if (w < 0) { putchar('-'); w = -w; }
while (w) {
*(pos++) = w % 10 + '0';
w /= 10;
}
while (pos != write_buf) putchar(*(--pos));
putchar(end);
}

这是我先前版本的模板中的快读快写的板子。可以看到一些局部变量使用了 static 。原指望可以加快速度,但是使用一段时间后就发现了输入正数变成负数,输出含有前导0的情况。什么原因呢?

static 设计之初的意图使用来保存函数上一次调用时的值,他的初始化是只会执行一次的。比如 static bool f = false; ,f变量只有在程序开始时会被复制为 false ,之后一但有一次变成了 true ,下一次调用是仍然会是 true ,就会导致接下来的输入都会变成负数。同样的,输出有前导0也是因为 pos 指针没有归0。

怎么解决呢?一种方法是弃用 static ,另一种方法是将复制和初始化分开,使用 static bool f; f = false ,但这样就没什么意思了。所以现在新版本的快读快写弃用了小变量的 static ,只保留了 buf 数组的 static 来避免每次调用重新申请的时间。

所以,特别是OIers一定要注意,不要只为了快而使用 static ,要理解这个关键字的真正用途。