views:

365

answers:

8

Sometimes you run into code that has extra brace brackets, that have nothing to do with scope, only are for readability and avoiding mistakes.

For example:

GetMutexLock( handle ) ; 
{
  // brace brackets "scope" the lock,
  // must close block / remember
  // to release the handle.
  // similar to C#'s lock construct
}
ReleaseMutexLock( handle ) ;

Other places I have seen it are:

glBegin( GL_TRIANGLES ) ;
{
  glVertex3d( .. ) ;
  glVertex3d( .. ) ;
  glVertex3d( .. ) ;
} // must remember to glEnd!
glEnd() ; 

This introduces a compiler error if the mutex isn't freed (assuming you remember both the } and the Release() call).

The question is:

  • 1 Is this a bad practice? Why?
  • 2 If it is not a bad practice, will it possibly change how the code is compiled? Possibly make it slower?
+2  A: 

It's not bad practice. It does not make anything slower; it's just a way of structuring the code.

Getting the compiler to do error-checking & enforcing for you is always a good thing!

tenfour
+1 for getting the compiler to do your work...
Hemal Pandya
unfortunately freeing the resource yourself is error-prone...
Matthieu M.
+1  A: 

Anything that improves readablity IMHO is good practice. If adding braces help with the readability, then go for it!

Adding additional braces will not change how the code is compiled. It won't make the running of the program any slower.

Starkey
{I {think {that {adding {braces {can {reduce} readability}}}}}}. Seriously, braces tell me "there's a control structure here". When there is none, I keep looking for it anyway for a moment. Causing me to spend cognition and a fraction of a second looking for something that isn't there isn't readability.
David Thornley
@David - I don't think the OP was thinking adding an arbitrary number of braces to the code as in your example. I was referring to the way the OP was using braces. Obviously adding braces as in your example does not help with readability.
Starkey
@Starkey: Using braces for any purpose other than indicating a control structure does not help with readability, as far as I'm concerned. This doesn't count as a control structure. Using them to limit the scope of a RAII-allocated resource is.
David Thornley
+14  A: 

Braces affect variable scope. As far as I know that is all they do.

Yes, this can affect how the program is compiled. Destructors will be called at the end of the block instead of waiting until the end of the function.

Often this is what you want to do. For example, your GetMutexLock and ReleaseMutexLock would be much better C++ code written like this:

struct MutexLocker {
  Handle handle;
  MutexLocker(handle) : handle(handle) { GetMutexLock(handle); }
  ~MutexLocker() { ReleaseMutexLock(handle); }    
};
...
{
  MutexLocker lock(handle);
  // brace brackets "scope" the lock,
  // must close block / remember
  // to release the handle.
  // similar to C#'s lock construct
}

Using this more C++ style, the lock is released automatically at the end of the block. It will be released in all circumstances, including exceptions, with the exceptions of setjmp/longjmp or a program crash or abort.

Zan Lynx
This is the right way to go.
DeadMG
You need to name the locker, or it's just a temporary that dies right away. And you should probably change the comments after it to match the new resource management.
GMan
The correct syntax is `MutexLocker handle;`, not `MutexLocker(handle);`.
KennyTM
@KennyTM Isn't it `MutexLocker lock(handle);`?
Pedro d'Aquino
@Pedro: Right. I thought `handle` was the variable name :P
KennyTM
I went in and fixed that. This was the most up-voted answer, and it shouldn't be that wrong. @Zan: I hope you don't mind.
sbi
@sbi, @GMan: Thanks. D'oh! I shouldn't have forgotten to write that.
Zan Lynx
+19  A: 

The braces themselves are fine, all they do is limit scope and you won't slow anything down. It can be seen as cleaner. (Always prefer clean code over fast code, if it's cleaner, don't worry about the speed until you profile.)


But with respect to resources it's bad practice because you've put yourself in a position to leak a resource. If anything in the block throws or returns, bang you're dead.

Use Scope-bound Resource Management (SBRM, also known as RAII), which limits a resource to a scope, by using the destructor:

class mutex_lock
{
public:
    mutex_lock(HANDLE pHandle) :
    mHandle(pHandle)
    {
        //acquire resource
        GetMutexLock(mHandle);
    }

    ~mutex_lock()
    {
        // release resource, bound to scope
        ReleaseMutexLock(mHandle);
    }

private:
    // resource
    HANDLE mHandle;

    // noncopyable
    mutex_lock(const mutex_lock&);
    mutex_lock& operator=(const mutex_lock&);
};

So you get:

{
  mutex_lock m(handle);
  // brace brackets "scope" the lock,
  // AUTOMATICALLY
}

Do this will all resources, it's cleaner and safer. If you are in a position to say "I need to release this resource", you've done it wrong; they should be handled automatically.

GMan
+1 for correctness... and this new SBRM acronym I didn't know of! Much better than RAII as far as expressing the intent goes. And there doesn't even seem to be a wikipedia page for it!
Matthieu M.
+2  A: 

It will make no difference to the compiled code, apart from calling any destructors at the end of that block rather than the end of the surrounding block, unless the compiler is completely insane.

Personally, I would call it bad practice; the way to avoid the kind of mistakes you might make here is to use scoped resource management (sometimes called RAII), not to use error-prone typographical reminders. I would write the code as something like

{
    mutex::scoped_lock lock(mutex);
    // brace brackets *really* scope the lock
}   // scoped_lock destructor releases the lock

{
    gl_group gl(GL_TRIANGLES); // calls glBegin()
    gl.Vertex3d( .. );
    gl.Vertex3d( .. );
    gl.Vertex3d( .. );
} // gl_group destructor calls glEnd()
Mike Seymour
+1  A: 

This is much more useful (IMHO) in C++ with object destructors; your examples are in C.

Imagine if you made a MutexLock class:

class MutexLock {
private:
    HANDLE handle;
public:
    MutexLock() : handle(0) {
        GetMutexLock(handle);
    }

    ~MutexLock() {
        ReleaseMutexLock(handle);
    }
}

Then you could scope that lock to just the code that needed it by providing an new scope with the braces:

{
    MutexLock mtx;  // Allocated on the stack in this new scope

    // Use shared resource
}
// When this scope exits the destructor on mtx is called and the stack is popped
joshperry
A: 

If you're putting code into braces, you should probably break it out into its own method. If it's a single discreet unit, why not label it and break it out functionally? That will make it explicit what the block does, and people who later read the code won't have to figure out.

Ron Romero
+3  A: 

The specific placement of { ... } in your original example serves purely as formatting sugar by making it more obvious where a group of logically related statements begins and where it ends. As shown in your examples, it has not effect on the compiled code.

I don't know what you mean by "this introduces a compiler error if the mutex isn't freed". That's simply not true. Such use of { ... } cannot and will not introduce any compiler errors.

Whether it is a good practice is a matter of personal preference. It looks OK. Alternatively, you can use comments and/or indentation to indicate logical grouping of statements in the code, without any extra { ... }.

There are various scoping-based techniques out there, some of which have been illustrated by the other answers here, but what you have in your OP doesn't even remotely look anything like that. Once again, what you have in your OP (as shown) is purely a source formatting habit with superfluous { ... } that have no effect on the generated code.

AndreyT
Seems you're the only one who's commented on the "compiler error" issue - well observed. My impression is that the poster has seen macros used like this:BEGIN_X // do stuffEND_Xwhere the BEGIN_X and END_X substitutions include their own { and }, such that a missing END_X does produce a compiler error. Ugly stuff.
Tony
@Tony: Boost has a few of those. I once got about a hundred pages worth of errors because I forgot one. "Ugly stuff" does not begin to describe it :)
Dennis Zickefoose