Be careful when defining variables in switch-case"

Source: Internet
Author: User

The classification in this article is C ++, So we hereby declare that the rules mentioned here only apply to C ++. For C language, there is a different set of rules.

Let's take a look at the following code. Is there a problem?

void RunStateMachine(){    switch(m_status)    {    case TASK_START:        int data = FormDataToSend();        m_mailbox->Send(data);        m_status = TASK_SENT;        break;    case TASK_SENT:        //..        break;    //..    }}

This is the prototype of some of the code written today. At first glance, there was no problem, but the compiler reported the error initialization of 'data' is skipped by 'case' label.

Switch-case Traversal"

I searched the internet and looked at the standards, and finally understood the ins and outs. In C ++, the case in switch-case is essentially a label, just like a goto label. The Code in case does not constitute a local scope, although its indentation gives people the illusion that it is a scope. That is to say, all the variable scopes defined in case are switch {...}, which can still be accessed in other cases. The switch is essentially equivalent to goto, so the print statement followed by the switch will never be executed.

Switch (selector) {cout <selector; Case selector_a: int I = 1; Case selector_ B: // I is still visible here}

So what does this have to do with errors? C ++ standard:

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point
Where it is in scope is ill-formed unless the variable has pod type (3.9)
And is declared without an initializer
. (The transfer from the condition of a switch statement to a case label is considered a jump in this respect .)

This means that if the execution path of a program jumps from point A in the Code (a local variable X is not defined yet) to another point B in the Code (this local variable X has been defined, the compiler reports an error. This skip can be caused by running the GOTO statement or switch-case.

There are two situations: first, for a pod object, an error is reported only when an initialized declaration is skipped.

Switch (selector) {Case selector_a: int I = 1; // if it is "int I;", the compiler will not report an error, only the following warning case selector_ B: cout <I; // warning: Use uninitialized I}

It is worth noting that whether the variable I is defined and the space size is determined during the compilation period, and Initialization is the action at runtime. Initialization is skipped, not its definition.

Second, for class objects with explicitly defined constructor, an error is reported when the declaration is skipped.

Class employee {public: employee () {...} void F () {...}; .. Switch (selector) {Case selector_a: employee e; // compilation error! Case selector_ B: E. F ();}

When a pod object has an initialization type or a class has an explicit constructor, it indicates that the programmer wants to initialize the object. If the program is executedAny possibleAs a result, the initialization is skipped, and the program may enter an unexpected incorrect state. Therefore, the standards explicitly prohibit such behavior.

Of course, for a pod object that has not been initialized, the subsequent reading may be problematic or not, depending on whether the value has been assigned before use. The compiler is powerless. Therefore, in most cases, no error is reported.

Void F (bool set) {goto label; int I; label: If (SET) {I = 3 ;}cout <I; // do I have initialization? }. F (false );

Now, let's go back to the problem. The root cause of the above compilation error is that the scope of the object is long and spans multiple cases. The solution is to use braces {} to encapsulate the code in each case into a local scope. Because I has a local scope, the Declaration is skipped.

Switch (selector) {Case selector_a: {int I = 1;} case selector_ B: // I is not visible here}

Goto's "traversal"

Another interesting example was found during the reading of the standard. This example is used to illustrate the problem of variable definition traversing forward, which has been discussed above. However, it is noted that the destructor of object A will be called during the execution of goto ly.

Void F (){//... goto lx; // compilation error. For the cause, see analysis //... ly: A = 1 ;//... lx: goto ly; // OK. Jumping to ly means that the destructor of A is called a B = A; // OK, which belongs to the scope of, but it will never be executed}

This program forms an endless loop. The first a structure is called, then constructed, destructed, and continuously reinsed. So why does a's destructor be called when running goto ly? This is also specifically described in the standard:

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.

When the program execution path leaves a loop, the local scope {...}, orBefore returning to an initialized object,The corresponding destructor is called.

This is understandable. In the above example, the scope of object a starts from a A = 1 and ends with the right parenthesis} of object F. If the execution of the program jumps to a A = 1, it is obviously not in the scope of. To exit the scope, you should naturally call the destructor of A, just as if an exception or return is thrown in the middle.

Summary

1. In switch-case, the switch is equivalent to goto, and the case is equivalent to a goto tag.

2. When defining variables in case, {...} must be added to the surrounding area to form a local scope; otherwise, an error is reported during compilation. Traditionally, the Code in case is always included in {...}, which is easy to use. It is one of the coding Convention of some companies.

Switch (selector) {Case selector_a: {int I;} case selector_ B: // I is not visible here}

3. When the Goto goes back through the initialization of an object, the destructor of the object is called.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.