dingmz_frc的博客
http://blog.163.com/dingmz_frcmyblog/blog/static/217304023201372085320739/void RunStateMachine() { switch(m_status) { case TASK_START: int data = 10; break; case TASK_SENT: //.. break; //.. } }
switch(selector) { cout << selector; case selector_a: int i = 1; case selector_b: // i在此仍然可见 }
switch(selector) { case selector_a: int i = 1; // 如果是"int i;",则编译器不报错,只有下面的警告 case selector_b: cout << i; // warning: 使用未初始化i }
class Employee { public: Employee() {..} void f() {..} }; .. switch(selector) { case selector_a: Employee e; // 编译报错! case selector_b: e.f(); }
[cpp] view plaincopyprint? void f(bool set) { goto label; int i; label: if (set) { i = 3; } cout << i; // i到底有没有初始化?只有运行时才知道 } .. f(false);
switch(selector) { case selector_a: { int i = 1; } case selector_b: // i在此不可见 }
goto的“穿越”
在翻看标准的时候,发现了另外一个有趣的例子。这个例子是为了说明向前穿越过变量的定义会有问题,这个在上面已经讨论过了。但是注释说,在执行goto ly的时候会调用对象a的析构函数。
void f() { // ... goto lx; // 编译出错,原因见上分析 // ... ly: A a = 1; // ... lx: goto ly; // OK, 跳跃到ly意味着a的析构函数被调用 A b = a; // OK, 这里属于a的作用域,但是永远不会执行到 }
这段程序形成了一个死循环,最先a的析构被调用,然后被构造,被析构,不断轮回。那么,为什么在执行goto ly的时候会调用a的析构函数呢?这个在标准里面也有专门说明:Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of variables with automatic storage duration that are in scope at the point transferred from but not at the point transferred to.
意思说:当程序执行路径离开一个循环、局部作用域{..}、或者回到一个已初始化对象之前时,相应的析构函数会被调用。
这是可以理解的,上例中对象a的作用域是从A a=1开始,到f的右括号}结束。如果程序执行跳到A a=1之前,显然已经不在a的作用域了。离开作用域自然应该调用a的析构函数,就像中途抛出一个异常或者return返回一样。
小结
1. switch-case中的switch相当于goto, case相当于一个goto标签。
2. 在case中定义变量时必须在周围加{..}以形成局部作用域,否则编译报错。习惯上总是将case中的代码用{..}括起来,比较省事。是有些公司的coding convention之一。
[cpp] view plaincopyprint? switch(selector) { case selector_a: { int i; } case selector_b: // i在此不可见 }
3. 当goto往回穿越过一个对象的初始化时,该对象的析构函数被调用。