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.
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.
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.
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.
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.
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With