1

So, some may agree that (code 1):

void func()
{
    int a, b;
    {
        //Do something with a and b
    }
}

Looks better (or is a better practice) than (code 2):

void func()
{
    int a;
    {
        int b;
        //Do something with a and b
    }
}

Also, than this (code 3):

void func()
{
    {
        int a, b;
        //Do something with a and b
    }
}

If there are no redeclarations of a or b are these codes equivalent? will the compiler optimize this?

Ivan
  • 1,352
  • 2
  • 13
  • 31
  • The compiler will create the same code in all these cases. From the compilers point of view, these variables will not exist after the brackets, unless they are referenced there. – Devolus Apr 07 '21 at 13:11
  • Thanks @Devolus , that's what I presumed, how could I prove this? or is it implicitly written somewhere in C++ doc? – Ivan Apr 07 '21 at 13:14
  • 1
    The compiler is free to rearrange code as long as the observable behavior is not changed. Since the variables are not used after that, the compiler can simply ignore them, which he most likely will in optimized code. You can always switch on assembly output and check what the compiler does. But of course, this only proves this particular implementation. – Devolus Apr 07 '21 at 13:15
  • 7
    @van In general the first example is a bad practice. Each variable should be declared in the minimal scope where it is used. – Vlad from Moscow Apr 07 '21 at 13:16
  • 1
    If you really want to see what the compiler does, you need to look at the assembly output. But it's rather pointless. The compiler can do what ever it wants, provided that the resulting program behaves as it should – Jabberwocky Apr 07 '21 at 13:17
  • @VladfromMoscow makes sense, although I thought the good practice was doing it as soon as posible (and if posible both at the same time) so that is easy to read. – Ivan Apr 07 '21 at 13:18
  • 2
    The practice of defining all your variables upfront comes from old `c` style code in which you had to do it. Thats no longer true in `c` and has never been true in `c++`. In fact, like Vald said, in `c++` its important to scope variables in the minimal scope possible to make it more efficient. – Mike Vine Apr 07 '21 at 13:20
  • 1
    https://stackoverflow.com/questions/6664471/observable-behaviour-and-compiler-freedom-to-eliminate-transform-pieces-c-co – Devolus Apr 07 '21 at 13:20
  • 1
    @Ivan There are some exceptions from the general practice for example when a while loop is more readable than a for loop. In this case you may declare a variable that could be used within the body of ta for loop before the while statement. – Vlad from Moscow Apr 07 '21 at 13:21
  • 1
    The relevant rule is called the [as-if rule](https://en.cppreference.com/w/cpp/language/as_if). – rustyx Apr 07 '21 at 13:21
  • Thanks, this is very usefull information :) – Ivan Apr 07 '21 at 13:25
  • What do you mean by "optimise"? The complier is taking C++ and generating e.g. x86 object code. If it decides to represent `a` as one register and `b` as another register, is that "optimising"? – Caleth Apr 07 '21 at 13:30

2 Answers2

2

For trivial types (and this has a technical meaning), the destruction/creation of them simply indicates where the compiler is guaranteed not to need to know what their values are. Any possible danging reference or pointers after the variable goes away can be "ignored" when optimizing.

So creating data in the smallest scope it will be used can sometimes result in the compiler making more optimal code. If "something" is a function that the compiler cannot see the details of which takes an integer by reference (or pointer), the compiler does not know how long it needs to keep that actual integer around in actual memory. But it is guaranteed (by the programmer) that after the end of the scope, it doesn't need that actual integer in actual memory.

Barring a case like that, no, there is no difference. Compilers do not have to actually create objects of type int when you ask for them; but sometimes they are forced to by other requirements.

In debug builds, compilers create variables where you ask for them and clean them up when you ask them to, because that makes stepping through the code and examining the program state easier.


For non-trivial types (basically, objects with vtables, or objects with constructors, or objects with destructors, or ones that contain non-trivial types in a recursive definition), object creation/destruction can have visible side effects, so when it happens can matter. The compiler can still move them around under the as-if rule (ie, the assembly only needs to act as-if it was what you wrote), so if it can prove that those non-trivial construction/destruction operations do not care when exactly they run (in a standard formal sense) they can be moved around by the compiler.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

In your example code equivalent because you use simple types, like int. But in general this can be false if you will use objects.

Consider following examples:

void func()
{
    SomeObj a, b;
    SomeOtherObj c;
    {
        //Do something with a and b
    }
}

In this case objects a and b can't be deleted before c since objects always deleted in reverse order of creation. Although theoretically, if there is no observable side effects some compilers probably can rearrange creation of a and b after c and delete it before end of function is reached.

In second case

void func()
{
    SomeObj a;
    SomeOtherObj c;
    {
        SomeObj b;
        //Do something with a and b
    }
}

b will be deleted as soon as scope is closed, but a will behave as in first case. For third case a will behave same as b in second.

sklott
  • 2,634
  • 6
  • 17
  • damn, i(ve never thought on "objects always deleted in reverse" I guess it's because they will be one after the other in memory? do you have a source where I can check this ou tin detail? – Ivan Apr 07 '21 at 13:34
  • 1
    "I guess it's because they will be one after the other in memory?" - No. This doesn't have anything to do with memory. You can look here, there is references to standard in comments: https://stackoverflow.com/questions/14688285/c-local-variable-destruction-order – sklott Apr 07 '21 at 13:39