在重新定义之前从外部作用域访问变量是否定义明确?

Is it well defined to access a variable from an outer scope before it is redefined?

此代码在 gcc-11 中编译时没有警告:

    int i{ 2 };
    {
        std::cout << i;   //prints 2
        int i{ 3 };
        std::cout << i;   //prints 3
    }

这是定义明确还是恰好有效?

是的,是的。第二个 i 的范围,以及它隐藏第一个 i 的区域,是从它的声明符 (1) 到封闭块。这与无效的原因相同:

{
    std::cout << i;
    int i{ 3 };
}

但是,当然,这肯定不会发生在任何 你的 代码中,因为作为专业开发人员,你知道最好不要使用 one-character 变量names(2) 除了非常短的循环,或者以混乱的方式重用变量名:-)


(1) 标准(C++20)在[=14中讨论了“声明点”、“潜在范围”和“作用域”的概念=],这是寻找规则的权威场所。

变量名存在于它们的声明点和它们的块结束(它们的潜在范围)之间,不包括它们被遮蔽的区域(遮蔽是潜在和实际范围的差异)。

int i{3} 的声明点实际上位于 i{ 之间(在声明之后但在初始化之前)。

这可能会导致一些微妙的问题,例如:

int i = 7;
{
    int i {i};
    // Value of i here is indeterminate.
}

并且通常足以避免阴影。


(2) 您不会 为变量名称中的每个字符支付 现金,所以最好不要吝啬:-)

Is this well defined or it just happened to work?

是well-defined。在 {...} 块内声明的变量范围从声明点开始,到右大括号结束。来自 this C++17 Draft Standard:

6.3.3 Block scope      [basic.scope.block]

1     A name declared in a block (9.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (6.3.2) and ends at the end of its block. A variable declared at block scope is a local variable.


This code compiles with no warnings in gcc-11

这让我很吃惊。 clang-cl 编译器(在 Visual Studio 2019 中,'borrowing' 来自 MSVC 的 /Wall 开关)给出了这个:

warning : declaration shadows a local variable [-Wshadow]

GCC 11.2 中同时使用 -Wall-Wpedantic 不会生成此警告;但是,明确地 添加 -Wshadow 确实可以。不确定 GCC 需要什么“通用”-Wxxx 开关才能显示它。