-1

In c++ you don't have to put braces {} inside cases in switch statements unless you're declaring a variable.

Consider the following code:

int Lesson82a() {
    int test = 1;
    switch (test) {
    case 1:
    {
        int i = 1;
        cout << i << "\n";
        cout << "Inside braces" << "\n";
        return 0;
    }
    case 2:
        cout << "2" << "\n";
    case 3:
        cout << "3" << "\n";
    }
    return -1;
}

int Lesson82b() {
    int test = 1;
    switch (test) {
    case 1:
    {
        int i = 1;
        cout << i << "\n";
    }
    cout << "Outside braces" << "\n";
    return 0;
    case 2:
        cout << "2" << "\n";
    case 3:
        cout << "3" << "\n";
    }
    return -1;
}

void Lesson82() {
    int test = Lesson82a();
    cout << test << "\n";
    test = Lesson82b();
    cout << test;
}

When running Lesson82() the output is as follows:

1
Inside braces
0
1
Outside braces
0

So the result is the same but does it make a difference?

  1. Should i put braces always wheather i declare a variable or not?
  2. If i put braces, does it matter if i put all my code for the case inside the braces? or only the code that needs the variable(s) i declare such as in Lesson82b() where i run some code and a return statement after the braces.
  3. Should i put break; after return even though it's then unreachable?

Does it make a difference when it is compiled?

On line 122 here: https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/begin/LearnWin32/BaseWindow/cpp/main.cpp#L122 i couldn't understand why the return statement is outside the braces.

I tried experimenting but i get the same results in my code regardless of it.

5
  • 1
    "...and what is best practices?..." is usually opinion based which is off-topic. Typical guidance for coding style is to follow the current projects style. Commented Aug 25 at 14:36
  • 1
    One question per post. Commented Aug 25 at 14:50
  • There is no "should" in this. There are options, and the "best" option depends on needs of your project and (since there are typically multiple options to achieve a required outcome) your opinion about what is "better". And opinions are like backsides - everyone has one, and they aren't all the same. Voting to close accordingly.
    – Peter
    Commented Aug 25 at 14:53
  • 1
    The more blatant issue is the fallthrough between case 2: and case 3:. Decide whether you actually intent case 2: to also execute the statements in case 3:. If so add the [[fallthrough]]; attribute at the end of case 2:. Otherwise add break;. This is to make it clear to the reader that the behavior is as intended and when you enable warnings properly, then the compilers should warn about it if you don't have either. And a missing default: case is usually also something that puts doubts on whether the behavior is as intended for all cases. Commented Aug 25 at 14:55
  • Follow the coding standard of your company or the code project, if there is one. If working on an existing project, attempt to be consistent with other code in the project. If you're creating a brand new project (sometimes including a course assignment), you get to choose a style that makes sense to you.
    – aschepler
    Commented Aug 25 at 16:00

2 Answers 2

2

Should i put braces always wheather i declare a variable or not?

Braces aren't needed in that case and unless you find it clearer that way, then no.

If i put braces, does it matter if i put all my code for the case inside the braces? or only the code that needs the variable(s) i declare such as in Lesson82b() where i run some code and a return statement after the braces.

No it doesn't. Only the code that needs access to the variable declared within the braces needs to be within the braces.

Should i put break; after return even though it's then unreachable?

No, that's completely unnecessary and doesn't improve reading in any way that I can see.

0

The switch statement’s cases do not require braces, period.

The purpose of braces is to create a local lexical context — that is, a space where one or more local variables may be created (and consequently given a specific, limited lifetime). In the case of a case clause in a switch statement, that lifetime must be limited. Consider:

switch (quux)
{
  case 1:
    int n = quux / 2;
    break;
  case 2:
    std::cout << "Hello " << n << "!\n";
    break;
}

If quux is 2, then what is the expected lifetime of n? Is it even created? When we attempt to print the value of n, is there even an n to print?

The answers are no. The targeted switch-case label jumps right over the code that creates it.

In C (before C23), it is a syntactic failure as well: the target of case labels must be a statement. But int n ... is a variable declaration.
Sorry, I misread your language tag as C. But I’ll leave this here since it is worthwhile info for C anyway.


We could move the declaration to before the switch. Let’s try it:

int n;
switch (quux)
{
  case 1:
    n = quux / 2;
    break;
  case 2:
    std::cout << "Hello " << n << "!\n";
    break;
}

Now when quux is 2 we jump right over the code that initializes n with a value. With your compiler warnings turned up, you should definitely see something like:

error: 'n' may be used uninitialized

...which is UB.


These two examples are bad code. (IOW, don’t do that.) They exist solely to demonstrate the problem.

But suppose you have a construct like this:

int n;
switch (quux)
{
  case 1:
    n = quux / 2;
    std::cout << n << "\n";
    break;
  case 2:
    std::cout << "Hello world!\n";
    break;
}

Surely life is better, right?

Maybe. But the problems already noted still exist. You cannot declare n local to where it is used, and in those cases where it is not used, it is uninitialized. I cannot say whether or not this is actually consequential, but it is still something the compiler must think about, so it is.

Aaaand, it is a good idea anyway to make local variables only exist when and for as little time as needed.


The solution: create a local context using { curly braces }. This has always been how it works in C and, consequently, C++. It has always been totally valid to do something like:

int main(void)
{
  int sum = 0;             // x does not exist
  {                        // (new local context)
    int x = 10;            // x exists!
    while (x) sum += x--;  // x exists!
  }                        // (end of scope: x is destroyed)
  printf( "%d\n", sum );   // x does not exist
  return 0;                // x does not exist
}

We can apply this knowledge to use in switch statements.

switch (quux)
{
  case 1:
    {
      int n = quux / 2;
      std::cout << n << "\n";
    }
    break;
  case 2:
    std::cout << "Hello world!\n";
    break;
}

This is perfectly fine and valid. The case clauses only contain statements. n only exists in a local context. Everything is clear and, importantly, easy for the compiler (and us humans) to reason about.


Now, return and break statements are attached to very specific brace-enclosed contexts. The return is attached to a function’s brace-enclosed context. The break is attached to a switch (or a loop’s) context. (It is not attached to a case!)

That means that the position of return or break relative to a local brace-enclosed context is irrelevant. Both are valid:

switch (quux)                       |  switch (quux)
{                                   |  {
  case 1:                           |    case 1:
  {                                 |      {
    int n = quux / 2;               |        int n = quux / 2;
    std::cout << n << "\n";         |        std::cout << n << "\n";
    break;                          |      }
  }                                 |      break;
  case 2:                           |    case 2:
    std::cout << "Hello world!\n";  |      std::cout << "Hello world!\n";
    break;                          |      break;
}                                   |  }

In both of these cases the local context is properly terminated before the break jumps control to the end of the entire switch statement.


The list of statements following a case label are like any other list of statements: they may contain brace-enclosed local contexts in any fashion you wish.

switch (quux)
{
  case 1:
    {
      std::cout << "inside\n";
    }
    std::cout << "outside\n";
    {
      std::cout << "inside again, lol\n";
    }
    break;
}

Just... try to write readable code. This leads us to the final bit:


Brace-enclosed spaces are easily elided by the compiler when they serve no purpose. So using braces for stylistic reasons is fine:

switch (quux)
{
  case 1:
  {
    int n = quux / 2;
    std::cout << n << "\n";
    break;
  }
  case 2:
  {
    std::cout << "Hello world!\n";
    break;
  }
}
4
  • 1
    Dang it! I thought I read C as the tag.
    – Dúthomhas
    Commented Aug 25 at 15:49
  • This answer appears to cover what the OP already knows and fails to address what was asked (i.e., given that braces are needed to create a lexical context for variable definitions, should braces be used in other situations).
    – JaMiT
    Commented Aug 25 at 16:18
  • @JaMiT Hmm, I was going to say I had (in the very first sentence, even), but re-reading the title Q, I think I have to agree. I’ll edit.
    – Dúthomhas
    Commented Aug 25 at 16:22
  • @JaMiT Edited .
    – Dúthomhas
    Commented Aug 25 at 16:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.