This episode will explain how you can use curly braces in C++ to create a new scope. You can use this ability to control name visibility and reduce name conflicts.
And you can also use curly braces to control exactly when object constructors and destructors are run. This is possible because C++ has very specific rules about when objects are constructed and destructed. Other languages that use garbage collection can’t give you this level of control.
If you’d like to improve your coding skills, then browse the recommended books and resources at the Resources page. You can find all my favorite books and resources at this page to help you create better software designs.
Listen to the full episode for more details or read the full transcript below.
Did you know that you can use curly braces for more than just function and loop bodies?
When writing a function, or a class, or an if statement, or a loop, C++ uses an opening curly brace to begin the body of the function, class, if/else statement, or loop. Then you put all the normal statements and close it all with a matching closing curly brace.
We get so used to this that we don’t usually notice the curly braces anymore. At least until we miss one and have to hunt through the code to find where it’s missing.
It helps to keep your braces aligned and your indentation consistent. It makes it easy to spot a missing curly brace. This is one of the reasons that I put curly braces on their own lines. I like mine unindented from the class, method, or loop and then indent the code inside them. That’s just my personal preference.
A lot of books place the opening curly brace at the end of the previous line which saves vertical space. This is important in books. And I think a lot of people become used to see code written this way and then write their own code the same.
This episode is not about where to put your curly braces though. The only thing I’ll suggest is that whatever style you like, at least be consistent. This episode is about something else. Something so obvious that many people are not even aware of it.
You see, not only are braces used to define the body of a class, method, or loop, they also define a scope.
If you declare a local variable inside a method, then that variable is scoped to that method. This means the compiler will only let you refer to the variable by name from within that method.
When the method begins, the variable is constructed. And when the method ends, the variable is destructed.
And you can do the same thing inside a loop. Only this time, the variable will be constructed and destructed on each pass through the loop.
And you can declare member variables inside a class definition which then get constructed whenever you create instances of the class and get destructed when the class instances get destructed.
The curly braces define the scope and how they’re used, either as part of a class, or a method, or a loop defines the lifetime of that scope.
The interesting thing is that you don’t need to write a new method or loop in order to get a new scope.
As long as you’re writing code inside a method, you can put matching opening and closing curly braces anywhere you want. They don’t have to be attached to an “if” statement or a “for” loop.
The real question is why would you want to do this?
The C++ language is very specific about when and in what order constructors and destructors will be called. When you need to adjust this order, then adding a new pair of curly braces might be just what you need.
The nice thing is that you’re not limited to using only the variables declared inside the curly braces. You just need to be aware that any variables you declare inside the curly braces won’t be available anymore once you leave.
Let’s say you declare an int type called count at the beginning of a method. You can use count from that point forward until the end of the method. You can pass it to other methods. You can use it inside if statements. And you can use it inside extra curly braces.
The only thing you can’t do is use any variables declared inside the curly braces once you leave the curly braces.
What happens if you declare another variable of any type within the curly braces also called count? This is also okay as long as you’re aware that count within the curly braces refers to the new one and not the one declared outside.
You can use this to your advantage if you ever need to declare a macro that needs its own variable.
By defining the macro to use its own scope with curly braces, then the variable name is guaranteed to not conflict with any other variable names.
Or maybe you want to use the same variable name multiple places within your method for different purposes and maybe with different types? I’d normally suggest not doing this but maybe you have a good reason. You can use separate scopes defined with curly braces to do this.
Maybe you’re writing code that will be used to generate more code. This sounds like computers programming themselves. But we’re not that advanced yet. You just want to write some routine code based on input that’s well understood. The problem is this code is tedious and easy to make mistakes. That’s a perfect job for a program to handle. This is the solution I created when designing a Google Protocol Buffers implementation. I needed a program that would read a message definition and create code that could serialize that message. Don’t worry if this part doesn’t make sense right now. The point is that I had C++ code that read an input file and generated more C++ code as output. This generated code can then be included in your projects to allow it to send messages to other applications.
Other than managing name collisions, you’ll be more likely to use curly braces to manage variable lifetimes like I started explaining before getting sidetracked. This is not very interesting for integral types but can get interesting for complex types. Especially your own classes.
If your class does some extra work during construction and maybe cleans up, or prints a message, or logs a time, etc. during destruction, then by declaring and using this class as a variable inside curly braces, you can control when all this work happens.