Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using curly braces to segregate a variable that I want to use multiple times in C++

In the code below, I have a while statement used to make sure an input string is less than 10 characters. I've declared a bool called cont which I use to tell the while loop to stop once my conditions have been met.

#include "stdafx.h"
#include <iostream>
#include <string>

int main()
{
    using namespace std;

    cout << "Enter a string less than 10 characters long: ";

    string teststring;

    {
        bool cont(false);

        //if input is 10 or more characters, ask for input again until it is less
        while (!cont)
        {
            getline(cin, teststring);

            if (teststring.length() >= 10)
            {
                cout << "Too long, try again: ";
            }
            else
            {
                cout << "Thank you.\n\n";
                cont = true;
            }

        }
    }

    return 0;
}

As you can see there, I've used a set of {}s to separate the code out, giving the cont variable a local scope within those braces. I did this so that if I ever wanted to use that variable name again, I could just re-declare it, and when I'm done with it, it's destroyed.

Is this an acceptable practice? Or is there a better way to do what I've done? I acknowledge that in this specific, basic scenario, the condition is simple enough that it's hardly necessary, but I may want to do this for more complex loops in the future.

like image 608
Eric David Sartor Avatar asked May 28 '15 06:05

Eric David Sartor


People also ask

What is the use of curly brackets in C programming?

In programming, curly braces (the { and } characters) are used in a variety of ways. In C/C++, they are used to signify the start and end of a series of statements. In the following expression, everything between the { and } are executed if the variable mouseDOWNinText is true. See event loop.

Why do braces have curly C?

Different programming languages have various ways to delineate the start and end points of a programming structure, such as a loop, method or conditional statement. For example, Java and C++ are often referred to as curly brace languages because curly braces are used to define the start and end of a code block.


4 Answers

In general? Yes. This is good.

In this specific case? No. Needless. You are not using that name again, and in this simple code you're not going to. So it's just noise.

See… it's a balance.

I find myself doing this quite a bit in functions that execute several related SQL statements. Each time I might build it up with a std::stringstream called ss. Sure, I could give each one a different name, but it entirely prevents errors to keep each statement builder in its own scope.

It's also a very common technique when you use things like lock guards.

like image 113
Lightness Races in Orbit Avatar answered Oct 21 '22 13:10

Lightness Races in Orbit


This is an acceptable practice and does exactly what you say. However it is rarely used because in small functions, it is unambiguous and therefore acceptable to have the cont variable in the function top-level scope. If you feel like you need to separate scope in a larger function, creating another function with an explicit name is generally preferred.

You can think of those braces as nameless functions only called once. If you see yourself using it a lot, perhaps you should give it a name of its own.

Another option is to rewrite the loop to not need the cont variable, for example:

string teststring;
do
{
    cout << "Enter a string less than 10 characters long: ";
    getline(cin, teststring);
} while (teststring.length() >= 10);

cout << "Thank you.\n\n";

But this is not always possible, especially if you need to output a different message depending on the stopping condition.

like image 38
fouronnes Avatar answered Oct 21 '22 11:10

fouronnes


Yes, it is fine, if you have a good reason to be re-using a variable. Lock guards are the most common usage in my own code, and the example given in Lightness's answer of std::stringstream ss. Basically do this any time that choosing a different variable names feels more awkward. E.g. if you are writing lock1, lock2, lock3, ... in your code.

However, more acceptable practice, would be to regard long function bodies as a code smell, and refactor them into their own functions. E.g.

...
string teststring;

{
    bool cont(false);
    //10 lines of code to handle the foo scenario
}
{
    bool cont(false);
    //15 lines of code to handle the bar scenario
}
...

This is better handled by refactoring to look like:

...
string teststring;
foo(teststring);
bar(teststring);
...

void foo(string &teststring){
bool cont(false);
//10 lines of code
}

void bar(string &teststring){
bool cont(false);
//15 lines of code
}
like image 39
Darren Cook Avatar answered Oct 21 '22 12:10

Darren Cook


This is a toy case obviously but this is a good practice and 'stand-alone' blocks are there for that purpose. I happen to believe they're a better way to structure long functions than breaking it down into members which (in many cases) have no separate purpose.

In such a case you can provide a faster, clearer, safer program particularly if there's a comment (possibly one line) introducing each block.

However in this case you might consider:

    for ( bool cont(false);!cont;)

Which has the same effect. Variables declared in a for(.;.;.) statement are confined to the scope of that statement.

In this case you can dodge the whole variable with:

    for(;;) //<--- Canonical formulation for 'infinite' loop.
    {
        getline(cin, teststring);

        if (teststring.length() >= 10)
        {
            cout << "Too long, try again: ";
        }
        else
        {
            cout << "Thank you.\n\n";
            break; //<--- Escapes the loop.
        }

    }

Footnote (in response to comments):

You should regard a for loop as 'syntactic sugar' on a while loop. That is no different in their performance, etc. and just pick the one that reads best. for(;cond;) just looks funny.

There may be a tiny (tiny) performance benefit to break but I happen to think it's actually simpler and more readable in many cases.

If the code were more complex there might be more 'loop end' code so it becomes:

for(bool cont(false);!cont;) {

    //Complex code with multiple 'exit' conditions...

    if(!cont) {
        //Go round again code that won't fit nicely in last term of for loop...
    }
}

Whereas using break just makes a 'swift exit' easier to understand. They're not (widely) considered to have the 'bad karma' of goto because they 'go to' a very clearly defined point of execution.

like image 26
Persixty Avatar answered Oct 21 '22 11:10

Persixty