What is the purpose of anonymous { } blocks in C style languages (C, C++, C#)
Example -
void function()
{
{
int i = 0;
i = i + 1;
}
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.
{ ... }
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.
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
}
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.
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();
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.