What is the purpose of anonymous { } blocks in C style languages?
Asked Answered
P

17

46

What is the purpose of anonymous { } blocks in C style languages (C, C++, C#)

Example -



void function()
{

  {
    int i = 0;
    i = i + 1;
  }

  {
    int k = 0;
    k = k + 1;
  }

}

Edit - Thanks for all of the excellent answers!

Primulaceous answered 1/2, 2009 at 1:48 Comment(1)
For completeness, you can do this in Java too.Preponderance
W
79

It limits the scope of variables to the block inside the { }.

Wolfy answered 1/2, 2009 at 1:50 Comment(0)
E
21

Brackets designate an area of scope - anything declared within the brackets is invisible outside of them.

Furthermore, in C++ an object allocated on the stack (e.g. without the use of 'new') will be destructed when it goes out of scope.

In some cases it can also be a way to highlight a particular piece of a function that the author feels is worthy of attention for people looking at the source. Whether this is a good use or not is debatable, but I have seen it done.

Eichler answered 1/2, 2009 at 1:53 Comment(0)
S
16

They are often useful for RAII purposes, which means that a given resource will be released when the object goes out of scope. For example:

void function()
{
    {
        std::ofstream out( "file.txt" );
        out << "some data\n";
    }
    // You can be sure that "out" is closed here
}
Succubus answered 1/2, 2009 at 1:57 Comment(0)
S
7

{ ... } opens up a new scope

In C++, you can use them like this:

void function() {
    // ...
    {
        // lock some mutex.
        mutex_locker lock(m_mutex);
        // ...
    }
    // ...
}

Once control goes out of the block, the mutex locker is destroyed. And in its destructor, it would automatically unlock the mutex that it's connected to. That's very often done, and is called RAII (resource acquisition is initialization) and also SBRM (scope bound resource management). Another common application is to allocate memory, and then in the destructor free that memory again.

Another purpose is to do several similar things:

void function() {
    // set up timer A
    {
        int config = get_config(TIMER_A);
        // ... 
    } 

    // set up timer B
    {
        int config = get_config(TIMER_B);
        // ...
    } 
}

It will keep things separate so one can easily find out the different building blocks. You may use variables having the same name, like the code does above, because they are not visible outside their scope, thus they do not conflict with each other.

Suber answered 1/2, 2009 at 1:54 Comment(0)
W
7

By creating a new scope they can be used to define local variables in a switch statement.

e.g.

switch (i)
{
    case 0 :
        int j = 0;   // error!
        break;

vs.

switch (i)
{
    case 0 :
    {
        int j = 0;   // ok!
    }
    break;
Webby answered 1/2, 2009 at 3:0 Comment(2)
@Ferrucio: Not only in switch statements. In C the variables should be defined in a scope before any instruction. So if you have a large function and need a temporary variable for a calculation, you could open a new scope anywhere in the function and define your temp variable.Pitre
@Valentin - that was true for K&R C and C89, but I think C99 allows you to declare and initialize variables as you need them (like C++) so you don't need to create scopes just for that. However, you still need to create a scope within a switch statement or the compiler may complain that the variable's initialization is skipped by one or more of the cases.Webby
S
7

Another common use is with OpenGL's glPushMatrix() and glPopMatrix() functions to create logical blocks relating to the matrix stack:

glPushMatrix();
{
    glTranslate(...);
    glPushMatrix();
    {
        glRotate(...);
        // draw some stuff
    }
    glPopMatrix();
    // maybe draw some more stuff
}
glPopMatrix();
Shanghai answered 1/2, 2009 at 4:10 Comment(1)
That seems like a good idea for C/C++. In C#, you'd do the same thing via the using construct, which would avoid forgetting to pop the matrix at the end, or leaving the stack messed up if an exception is raised.Preponderance
N
6
class ExpensiveObject {
public:
    ExpensiveObject() {
        // acquire a resource
    }
    ~ExpensiveObject() {
        // release the resource
    }
}

int main() {
    // some initial processing
    {
        ExpensiveObject obj;
        // do some expensive stuff with the obj
    } // don't worry, the variable's scope ended, so the destructor was called, and the resources were released
    // some final processing
}
Niobic answered 1/2, 2009 at 2:2 Comment(0)
S
5

Scoping of course. (Has that horse been beaten to death yet?)

But if you look at the language definition, you see patterns like:

  • if ( expression )   statement
  • if ( expression )   statement   else   statement
  • switch ( expression )   statement
  • while ( expression )   statement
  • do   statement   while ( expression ) ;

It simplifies the language syntax that compound-statement is just one of several possible statement's.


compound-statement:   { statement-listopt }

statement-list:

  • statement
  • statement-list   statement

statement:

  • labeled-statement
  • expression-statement
  • compound-statement
  • selection-statement
  • iteration-statement
  • jump-statement
  • declaration-statement
  • try-block
Stocktaking answered 1/2, 2009 at 8:20 Comment(1)
Yeah, people often forget that if (...) {...} else {...} or for(...) {...} are also using anonymous blocks. In fact this question was phrased as if based on that premise.Goldy
A
4

They're very often used for scoping variables, so that variables are local to an arbitrary block defined by the braces. In your example, the variables i and k aren't accessible outside of their enclosing braces so they can't be modified in any sneaky ways, and that those variable names can be re-used elsewhere in your code. Another benefit to using braces to create local scope like this is that in languages with garbage collection, the garbage collector knows that it's safe to clean up out-of-scope variables. That's not available in C/C++, but I believe that it should be in C#.

One simple way to think about it is that the braces define an atomic piece of code, kind of like a namespace, function or method, but without having to actually create a namespace, function or method.

Aldercy answered 1/2, 2009 at 1:51 Comment(0)
R
4

You are doing two things.

  1. You are forcing a scope restriction on the variables in that block.
  2. You are enabling sibling code blocks to use the same variable names.
Redan answered 1/2, 2009 at 1:56 Comment(0)
B
3

As far as I understand, they are simply for scoping. They allow you to reuse variable names in the parent/sibling scopes, which can be useful from time to time.

EDIT: This question has in fact been answered on another Stack Overflow question. Hope that helps.

Bentham answered 1/2, 2009 at 1:51 Comment(0)
L
3

As the previous posters mentioned, it limits the use of a variable to the scope in which it is declared.

In garbage collected languages such as C# and Java, it also allows the garbage collector to reclaim memory used by any variables used within the scope (although setting the variables to null would have the same effect).

{
    int[] myArray = new int[1000];
    ... // Do some work
}
// The garbage collector can now reclaim the memory used by myArray
Lastly answered 1/2, 2009 at 1:58 Comment(1)
Actually, depending on the GC implementation, the JIT should already know that there are no more reads on that variable, and hence it is already eligible for collection.Sawmill
P
2

A useful use-cas ihmo is defining critical sections in C++. e.g.:

int MyClass::foo()
{    
   // stuff uncritical for multithreading
   ...
   {
      someKindOfScopeLock lock(&mutexForThisCriticalResource);
      // stuff critical for multithreading!
   }
   // stuff uncritical for multithreading
   ...    
}

using anonymous scope there is no need calling lock/unlock of a mutex or a semaphore explicitly.

Pitre answered 1/2, 2009 at 1:48 Comment(0)
A
2

It's about the scope, it refers to the visibility of variables and methods in one part of a program to another part of that program, consider this example:

int a=25;
int b=30;
{ //at this point, a=25, b=30
     a*=2; //a=50, b=30
     b /= 2; //a=50,b=15
     int a = b*b; //a=225,b=15  <--- this new a it's
                  //                 declared on the inner scope
}
//a = 50, b = 15
Advantageous answered 1/2, 2009 at 1:57 Comment(0)
D
2

If you are limited to ANSI C, then they could be used to declare variables closer to where you use them:

int main() {
    /* Blah blah blah. */
    {
        int i;
        for (i = 0; i < 10; ++i) {
        }
    }
}

Not neccessary with a modern C compiler though.

Dixson answered 1/2, 2009 at 2:7 Comment(2)
Yes, and sometimes it's merely a visual thing. Also worth noting that anything inside the braces is considered "a statement" for those syntax constructs that "accept only a single statement".Bridewell
@Valentin: Yes, in C++ you are allowed to declare variables anywhere, and not just at the top of a block.Dixson
D
0

I use it for blocks of code that need temporary variables.

Driven answered 1/2, 2009 at 13:12 Comment(0)
E
0

One thing to mention is that scope is a compiler controlled phenomenon. Even though the variables go out of scope (and the compiler will call any destructors; POD types are optimised immediately into the code), they are left on the stack and any new variables defined in the parent scope do not overwrite them on gcc or clang (even when compiling with -Ofast). Except it is undefined behaviour to access them via address because the variables have conceptually gone out of scope at the compiler level -- the compiler will stop you accessing them by their identifiers.

#include <stdio.h>
int main(void) {
  int* c;
  {
    int b = 5; 
    c=&b;
  }
  printf("%d", *c); //undefined behaviour but prints 5 for reasons stated above
  printf("%d", b); //compiler error, out of scope
  return 0;
}

Also, for, if and else all precede anonymous blocks aka. compound statements, which either execute one block or the other block based on a condition.

Expatiate answered 11/4, 2020 at 13:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.