22 March 2023

C++ 核心指南目录

“Do not reuse names in nested scopes”

理由

太容易搞错了。导致维护上的麻烦。

坏例子

int d = 0;
// ...
if (cond) {
    // ...
    d = 9;
    // ...
}
else {
    // ...
    int d = 7;
    // ...
    d = value_to_be_returned;
    // ...
}
return d;

如果这里的 if 代码段很长的话,很容易忽视内部作用域引入的 d。这是很常见的 bug。有时候,这种内部作用域引入同名变量,称为“shadowing遮蔽”。

注意

当函数很长很复杂的时候,shadowing 是常见的问题。

例子

C++ 语言不允许对最外层的函数参数做 shadowing。

void f(int x)
{
    int x = 4;  // error: reuse of function argument name

    if (x) {
        int x = 7;  // allowed, but bad
        // ...
    }
}

坏例子

局部变量重用成员变量名也容易出问题:

struct S {
    int m;
    void f(int x);
};

void S::f(int x)
{
    m = 7;    // assign to member
    if (x) {
        int m = 9;
        // ...
        m = 99; // assign to local variable
        // ...
    }
}

例外

我们经常在派生类中重用基类函数名:

struct B {
    void f(int);
};

struct D : B {
    void f(double);
    using B::f;
};

不过,这样也容易出错。比如,如果我们忘记用 using 声明,调用 d.f(1) 就找不到参数为 int 类型的 f 函数。

强化

  • 标记在嵌套局部作用域重用变量名的情况
  • 标记在成员函数内重用成员变量名的情况
  • 标记把全局变量重用到局部变量或成员变量名的情况
  • 标记派生类中重用基类成员变量名的情况(函数名除外)