Home > Net >  C primer 5th edition switch statement
C primer 5th edition switch statement

Time:10-04

In C primer 5th edition the solutions appendix, gives an example about switch statement:

 case true:
     string file_name; // error: control bypasses an implicitly initialized variable.
     ...
 case false:
     if(file_name.empty()); // file_name is in scope but wasn't initialized.

But I think it is wrong because file_name has been implicitly initialized and that is why the compiler flags that error.

struct Foo{};
switch(val){
    case 1:
       Foo f; // ok not-implicitly initialized like std::string
    break;
    case 2:
        f.some_member(); // use f;
}

So are my guesses correct?

CodePudding user response:

The term "implicit initialization" sounds technical. But it's gobbledygook. It means nothing.

And the compiler doesn't use this made-up term either. To wit:

int main()
{
    struct Foo {
        void some_member() {}
        int a = 1;
    };
    int val = 0;
    switch (val){
        case 1:
            Foo f;
            break;
        case 2:
            f.some_member(); // use f;
    }
}

Compiler output:

<source>: In function 'int main()':
<source>:12:14: error: jump to case label
   12 |         case 2:
      |              ^
<source>:10:17: note:   crosses initialization of 'main()::Foo f'
   10 |             Foo f;
      |                 ^

And that's all. Initialization, plain and simple. When you remove the initializer for the member Foo::a, there's no more initialization, and the compiler will be OK with that:

int main()
{
    struct Foo {
        void some_member() {}
        int a;
    };
    int val = 0;
    switch (val){
        case 1:
            Foo f; // OK - no initialization at all
            break;
        case 2:
            f.some_member(); // use f
            if (f.a) {};     // undefined behavior, a is uninitialized here
    }
}

Now, f.a is not initialized, and that's OK unless you attempt to use its value. The access to f.a doesn't cause a compile-time failure, but is undefined behavior, just as-if you wrote the following:

int main() {
   int a;
   if (a) {} // undefined behavior, a isn't initialized
}

Modern compilers can and will use the uninitialized variable/member access as an optimization hint. The code that uses the uninitialized value may be removed, for example.

CodePudding user response:

According for example to the C 17 Standard (9.7 Declaration statement)

3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps91 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer

The class std::string does not has a trivial default constructor and a trivial destructor.

In this code snippet

struct Foo{};
switch(val){
    case 1:
       Foo f; // ok not-implicitly initialized like std::string
    break;
    case 2:
        f.some_member(); // use f;
}

the class Foo has a trivial default constructor and a trivial destructor.

and for example (15.1 Constructors)

6 A default constructor is trivial if it is not user-provided and if:

(6.1) — its class has no virtual functions (13.3) and no virtual base classes (13.1), and

(6.2) — no non-static data member of its class has a default member initializer (12.2), and

(6.3) — all the direct base classes of its class have trivial default constructors, and

(6.4) — for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.

Otherwise, the default constructor is non-trivial.

  • Related