c++ - 为什么 switch 构造中的声明是合法的?
问题描述
我发现了多个关于在switch
构造中定义变量的问题,但我还没有找到这个问题的明确答案。
C++ Primer 一书的第 5.3.2 章说如下:
正如我们所见,switch 中的执行可以跨越 case 标签。当执行跳转到特定情况时,在该标签之前发生在开关内的任何代码都将被忽略。
考虑到这些信息,我不明白为什么下面的示例是合法的。如果控制跳转到false
案例,它应该忽略true
案例。这意味着,分配给i
应该是非法的,因为它从未被声明过。为什么这个构造是合法的?
case true:
int i;
break;
case false:
i = 42;
break;
解决方案
声明是编译时的事情,运行时发生的事情与该事实无关。 在其声明后的同一或子范围内的i
任何点都可见。
没有什么会导致两个案例之间的范围更改,因此无论案例是否执行i
,案例中都保持可见。false
true
这就是为什么您可能会看到匿名块 ( { }
) 用于在 switch 案例中人为地限制范围。这是为了防止这个潜在的问题(尽管在这种情况下它不是问题)。
case true: {
int i;
break;
} // Closing this block causes the end of i's lifetime.
case false: {
i = 42; // Compile-time error; i is no longer in scope.
break;
}
请注意,您的代码仅通过初始化i
. 跳转不能在任一方向跨越初始化。
case true:
int i = 0;
break;
case false: // error: jump to case label crosses initialization
i = 42;
break;
此外,任何非 平凡类型的变量都不能具有跨越生命周期的情况,即使它没有显式初始化。
case true:
std::string i;
break;
case false: // error: jump to case label crosses initialization
i = "42";
break;
在这种情况下,解决方法是使用匿名块来限制声明的范围i
不跨越多个案例。
相关标准:
可以转移到一个块中,但不能通过初始化绕过声明的方式。除非变量具有标量类型、具有普通默认构造函数和普通析构函数的类类型,否则从具有自动存储持续时间的变量不在范围内的点跳转到它在范围内的点的程序*,这些类型之一的 cv 限定版本,或上述类型之一的数组,并且在没有初始化程序的情况下声明。
-- C++14 (N4296) [stmt.dcl.3]
关于跳跃的脚注(*):
从
switch
语句的条件到case
标签的转移在这方面被认为是一个跳跃。
推荐阅读
- python-3.x - 如何标记编码包含数字和字符串的 DataFrame 列?
- ruby-on-rails - 尝试更新,如果更新失败则删除(RubyOnRails-PostgreSQL)
- android - 从通知设置警报
- python - 如何获取 Celery 的 app.control.broadcast 的工作人员地址
- maven - 将 pom 文件上传到 Nexus 3 并收到错误“提供的 POM 文件无效”
- oop - 这是否违反了单一责任原则?
- xml - domnode不能在matlab中写入xml
- c# - 是否可以在仅具有公共链接的容器中列出 Azure Blob?
- laravel - 有什么方法可以在 laravel 的 create 方法中获取 id
- c# - 异步计算richtextbox行数