5

Technically, in C++ we have the possibility to use curly-braces to declare a new scope. For example in this function, which swaps two numbers

void swap_int(int& first, int& second)
{
   int temp = first;
   first = second;
   second = temp;
}

we could also declare temp inside its own block:

void swap_int(int& first, int& second)
{
   // Do stuf...
   {
      int temp = first;
      first = second;
      second = temp;
   }
   // Do other stuff...
}

This obviously has the advantage that temp is deleted directly when it is not needed anymore.

However, in the code I write I never use it. Also, in code from 3rd-party libraries I almost never see it at all.

Why is it not used publically? Does it bring any performance increase at all, or does it just mean additional typing-work?

Bobface
  • 2,782
  • 4
  • 24
  • 61
  • I almost never at all see a "temp" named variable. Doesn't mean it is bad or anything. Personally, I don't like the looks of a line brace in the wood, I even think it looks better if you say `/* Do stuff ... */ { ... }`, so that the opening brace is not alone. – Johannes Schaub - litb Jun 04 '16 at 17:28
  • @AlanStokes: In what way is this a "duplicate" of that? – Lightness Races in Orbit Jun 04 '16 at 17:44
  • @Lightness Well, to me the question is near identical and the answers look apposite. You are of course free to disagree. – Alan Stokes Jun 04 '16 at 17:46
  • @AlanStokes: The questions are completely different except that they relate to the scope-limiting feature of braces. That one is "what does this feature do?" This one is "why is this not popular?" – Lightness Races in Orbit Jun 04 '16 at 17:48
  • @Lightness I'm not convinced. But feel free to reopen. (Although it may then get closed as primarily opinion based if you are right.) – Alan Stokes Jun 04 '16 at 17:50
  • @Lightness Why would you use it without a reason? And the reasons are fairly rare. – Alan Stokes Jun 04 '16 at 17:51
  • 1
    @AlanStokes I also disagree that it is a dupe, as on the other question none of the answers mentions any reason not to use it which is actually what this question is asking for – 463035818_is_not_an_ai Jun 04 '16 at 17:58
  • Re: "... has the advantage that temp is deleted ..." no, `temp` is not **deleted**. It gets **destoyed** at the end of the scope. – Pete Becker Jun 04 '16 at 18:06
  • 1
    @PeteBecker and just to add a bit more of ironical fun I made a typo in my comment **too** ... – 463035818_is_not_an_ai Jun 04 '16 at 18:48
  • 2
    @tobi303 - um, insisting on correct terminology is not nitpicking. As Mark Twain said, "The difference between the almost right word and the right word is really a large matter. ’tis the difference between the lightning bug and the lightning." – Pete Becker Jun 04 '16 at 19:03
  • 1
    @PeteBecker actually I completely agree with you. Using the right terms is really important. Nevertheless I found it a bit funny ;) – 463035818_is_not_an_ai Jun 04 '16 at 19:07
  • Related question [here](http://programmers.stackexchange.com/questions/302217/using-compound-statements-blocks-to-enforce-variable-locality) (language agnostic) which is marked duplicate of [this](http://programmers.stackexchange.com/questions/200709/is-the-usage-of-internal-scope-blocks-within-a-function-bad-style) (tagged c# although the discussion may not be specific to one language). – eerorika Jun 04 '16 at 19:12
  • @user2079303: The closest C# equivalent to a C++ block `{ }` is the C# scoped-disposal block `using (...) { }` C# lexical-scope blocks really share very little behavior with C++ blocks, only the syntax. – Ben Voigt Jun 04 '16 at 23:40
  • @BenVoigt Considering that, would you then suggest re-opening the non c# question as non-duplicate of the C# one due to the different behaviour in different languages? – eerorika Jun 04 '16 at 23:56
  • `temp` is not deleted in any runtime sense. It falls out of scope at compile-time, but the slot in the stack frame is still there. If it was an object it would be destructed at the closing brace, but it isn't. – user207421 Nov 02 '19 at 05:42

2 Answers2

3

I don't see anything wrong per-se with naked brackets. They're a part of the language, and they're well defined. Historically, one place I have found them useful is when working with code that uses status codes instead of exceptions, while keeping const goodness:

const StatusCode statusCode = DoThing();
if (statusCode == STATUS_SUCCESS)
    Foo();
else
    Bar();

const StatusCode statusCode2 = DoAnotherThing();  // Eww variable name.
...

The alternative would be:

{
    const StatusCode statusCode = DoThing();
    if (statusCode == STATUS_SUCCESS)
        Foo();
    else
        Bar();
}

{
    // Same variable name, used for same purpose, easy to
    // find/replace, and has const guarantees. Great success.
    const StatusCode statusCode = DoAnotherThing();
    ...
}

The same applies to objects such as thread lockers that use RAII as well (Mutex objects, semaphores, etc), or generally any kind of resource that you may want to have an extremely short lifetime (file handles, for example).

Personally, I think the reason it's rare is that it can be indicative of a code smell (although not always). Where there are naked brackets, there may be an opportunity to factor out a function.

To take your example, if there is more than one job for swap_int, then the function is doing more than one thing. By extracting the actual swap code into another function, you can encourage reuse! For example:

template <typename T>
void swap_anything(T &first, T& second)
{
    T temp = first;
    first = second;
    second = temp;
}

// -------------------------------------------

void swap_int(int& first, int& second)
{
   // Do stuff...
   swap_anything(first, second);

   // Do other stuff...
}
jkeys
  • 3,803
  • 11
  • 39
  • 63
Karl Nicoll
  • 16,090
  • 3
  • 51
  • 65
1

Sometimes it's good practice (although I dislike that term, as it's subjective and context-specific), but like many things in life, taking it to the extreme (on either end of the spectrum) is a bad idea.

You'll see new scopes introduced sometimes in C++ where RAII is important, like when dealing with thread locks. Sometimes the precise moment of when an object is created and destroyed is very important and needs to be controlled. In those situations, introducing a new scope is a very useful and often-used way of accomplishing this.

But that's not frequently the case. Most of the objects we (the broad programming community) use don't have strict lifetimes that need to be so carefully managed. As such, it's not worth arbitrarily introducing new scopes to manage lifetimes of objects whose lifetimes aren't worth micromanaging.

If you do, you'll decrease the signal-to-noise ratio, and people will have a hard time telling which scopes are introduced to carefully control important resources, and which scopes are not. This can make it easy to introduce bugs when refactoring or developing code across teams. At the very least, you'll make programming a whole lot more tedious, which sucks, and you should generally avoid that if you can or else a violent psychopath may take it out on you.

Cornstalks
  • 37,137
  • 18
  • 79
  • 144