Unnecessary Curly Braces in C++

Do unnecessary curly braces reduce performance?

Most of the time it doesn't make any difference - and you should definitely code for readability more than anything else.

However, curly braces can have an effect on performance, in a surprising way, although it's pretty unusual. Consider this code:

using System;
using System.Collections.Generic;

class Test
{
static void FewerCurlies()
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 100; i++)
{
int x;
if (i % 3 == 0)
{
actions.Add(() => x = 10);
}

int y;
if (i % 3 == 1)
{
actions.Add(() => y = 10);
}
}
}

static void MoreCurlies()
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 100; i++)
{
{
int x;
if (i % 3 == 0)
{
actions.Add(() => x = 10);
}
}

{
int y;
if (i % 3 == 1)
{
actions.Add(() => y = 10);
}
}
}
}
}

The extra braces in MoreCurlies look redundant, right? Not quite... the generated code looks more like this:

using System;
using System.Collections.Generic;

class Test
{
static void FewerCurlies()
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 100; i++)
{
FewerCurliesCapture capture = new FewerCurliesCapture();
if (i % 3 == 0)
{
actions.Add(capture.Method1);
}

if (i % 3 == 1)
{
actions.Add(capture.Method2);
}
}
}

static void MoreCurlies()
{
List<Action> actions = new List<Action>();
for (int i = 0; i < 100; i++)
{
{
MoreCurliesCapture1 capture = new MoreCurliesCapture1();
if (i % 3 == 0)
{
actions.Add(capture.Method);
}
}

{
MoreCurliesCapture1 capture = new MoreCurliesCapture2();
if (i % 3 == 1)
{
actions.Add(capture.Method);
}
}
}
}

private class FewerCurliesCapture
{
public int x;
public int y;

public void Method1()
{
x = 10;
}

public void Method2()
{
y = 10;
}
}

private class MoreCurliesCapture1
{
public int x;

public void Method()
{
x = 10;
}
}

private class MoreCurliesCapture2
{
public int y;

public void Method()
{
y = 10;
}
}
}

The differences here are:

  • An instance of the capture class is created in each iteration of the loop in FewerCurlies, even if it's not used
  • Each instance of the capture class used in FewerCurlies contains both variables, even though each delegate will only actually use one of them, whereas in MoreCurlies each capture class only captures a single variable

This is all somewhat implementation-specific, but it shows that redundant-looking curlies can have an impact.

Unnecessary curly braces in C++

It's sometimes nice since it gives you a new scope, where you can more "cleanly" declare new (automatic) variables.

In C++ this is maybe not so important since you can introduce new variables anywhere, but perhaps the habit is from C, where you could not do this until C99. :)

Since C++ has destructors, it can also be handy to have resources (files, mutexes, or whatever) automatically released as the scope exits, which can make things cleaner. This means you can hold on to some shared resource for a shorter duration than you would if you grabbed it at the start of the method.

Does adding unnecessary curly brackets { } in a c++ program slow it down at all?

No it does not.

In general, due to the "as if"-rule, the compiler has a lot of leeway to optimize things.

Still, it is a style issue, and there are seldom straight answers everyone agrees on.

There are people who only use braces of any kind if they either significantly clarify the code or are neccessary, and those who always use a code block for conditionals and loops.

If you work in a team/on contract/on an inherited codebase, try to conform to their style, even if it's not yours.

Function of curly bracket without keyword unclear

Normally they'd be used to constrain scope of a variable, but in with your example Aux_U16 = 16; no new variable is defined, so there must be a pre-existing variable named Aux_16, and beyond the end of the block it will continue to have whatever value it was last set to within the block.

Limiting the scope allows you to create, for example, a new variable named i, without needing to think about the state of any i outside of that block -- unfortunately, as in the example you gave, the compiler wouldn't notice the difference between definition and assignment, and you could end up corrupting a variable you thought you had protected.

The other common reason to find things that way is simply cut-and-paste. There's nothing wrong with free-standing blocks like this, and sometimes people just forget to delete the leftovers. Or they might have had temporary variables in there until they edited the code and they went away. Or they might mean it as a note to themselves that the code inside the block belongs together.

c++ {*this} inside curly braces

The difference between the two is really quite subtle. C++11 introduced the feature list initialization (also sometimes called brace initialization):

Before C++11, when you want to default-construct and object o of type Obj and construct a Position p from o, you had to write

Obj o;              // default construct o
Obj::Position p(o); // construct p using Position(Obj const&)

A common error for beginners (especially with a Java background) was to try to write this:

Obj o();            // mistake: declares a function o returning an Obj
Obj::Position p(o); // error: no constructor takes a function

The first line declares a function, and the second one tries to create a Position using a constructor that takes a function pointer as its argument. In order to have a uniform initializer syntax, C++11 introduced list initialization:

Obj oo{};             // new in C++11: default construct o of type Obj
Obj::Position p1(oo); // possible before (and after) C++11
Obj::Position p2{oo}; // new in C++11: construct p2 using Position(Obj const&)

This new syntax also works in return-statements, and this leads to the answer of your question: the difference between return {*this}; and return *this; is that the former initializes the return value directly from *this, whereas the latter first converts *this to a temporary Position object and then initializes the return value indirectly from this temporary, which fails because both the copy- and move-constructor have been explicitly deleted.

As the previous posters have noted, most compilers elide these temporary objects because they aren't really useful for anything; but this is only possible if they could be used in theory because either a copy or a move constructor is available. Because this leads to a lot of confusion (why do I need braces around my return statement? is the compiler going to elide the copy or not?), C++17 does away with these unnecessary temporaries, and initializes the return value directly in both cases (return {*this}; and return *this).

You can try this using a compiler that supports C++17. In clang 4.0 or gcc 7.1, you can pass --std=c++1z, and your code should compile fine with and without braces.

Why is it considered a bad practice to omit curly braces?

Actually, the only time that's ever really bit me was when I was debugging, and commented out bar():

if(foo)
// bar();
doSomethingElse();

Other than that, I tend to use:

if(foo) bar();

Which takes care of the above case.

EDIT Thanks for clarifying the question, I agree, we should not write code to the lowest common denominator.



Related Topics



Leave a reply



Submit