I am playing around a little with for loops , tried the following code and got an infinite loop.
#include<iostream>
int main(){
int i {0};
bool condition = i < 5;
for ( ; condition ; ){
std::cout << "Hello World!" << std::endl;
i++;
}
}
Can someone explain why ?
bool condition = i < 5;
This line defines a variable named condition which has the value true from this line onwards.
It does not bind the expression from the right side, but only copies the result at the time of assignment.
What you intended is more complicated:
auto condition = [&i](){ return i < 5; };
for ( ; condition() ; )
Now condition is a function object which can be evaluated repeatedly.
The right hand of the assignment is called a lambda expression, and follows the form [capture scope](parameters){ body with return statement }.
In the capture scope, you can list variables either by value (without &) in which case they get copied once when the lambda is declared, or by reference (with leading &) in which case they don't get copied but the variable inside the lambda is a reference to the variable of the same name outside the lambda. There is also the short form [&] which captures all variables in the parent scope by reference, and [=] which captures everything by value.
auto can be used for brevity in combined declarations + assignments, and automatically resolves the type of the variable from the right hand side.
The closest compatible type you could explicitly specify would be std::function<bool(void)> (generic container for functions with that signature), the actual type of that object is some internal type representing the naked lambda which you can't write explicitly. So if you can't know the exact type, and you don't want to use a generic container type, auto is occasionally even necessary.
Variables in C++ store values. You seem to be under the impression that condition somehow remains connected to the expression i < 5. It is not. Once you set the value which is true at the time of the assignment it will keep that value until you change it. You never change it again so the value of condition is forever true.
citing cppref:
Executes init-statement once, then executes statement and iteration-expression repeatedly, until the value of condition becomes false. The test takes place before each iteration.
Now, your condition evaluates to true:
bool condition = i < 5; // true
hence, the loop will continue until false, which does not happen in the loop body of your code; condition is not written to after initialization, and therefore the loop will not stop.
The for loop runs on a condition, such as while i is below a specified value, and will keep running until this is no longer satisfied. In your case, it is never satisfied, guaranteeing an infinite loop.
Related
I have a function:
int f(std::atomic<bool>& flag);
That needs to check the value of flag, an atomic bool which gets changed by another thread. This function works as expected (f sees changes to the flag made by the other thread) if I call it like so:
f(m_flag1);
What I am trying to achieve now, is slightly more complicated, since I don't want to pass a reference to a single atomic bool, but to an expression instead, like:
std::atomic<bool> x = m_flag1 && m_flag2;
f(x);
As far as I understood, it would be wrong to directly pass the expression to the function, since that would be a temporary value that would gets destroyed once the function is called. It seems to me that r-values cannot be passed as reference too.
Having a reference to x does not help much, though, since I think the expression is only evaluated once, so f is not actually seeing m_flag1 && m_flag2.
What is a clean way to get a reference to an expression? Should my other thread continuously evaluate x = m_flag1 && m_flag2; or is there a cleaner way?
From question comments:
"[...]that fuction needs to check a boolean expression[...]"
emphasis mine
If your function is not supposed to modify the boolean flags but only evaluate its value, then you can just take the parameter as a const reference instead.
int f(const std::atomic<bool> & flag)
{
// ...
}
And the call may be like:
int result = f(flag1 && flag2);
Note: If you need to evaluate both flags "at the same time" (which is most probably the case), you'll need to add a synchronization mechanism such as mutexes because the expression evaluation flag1 && flag2 is not atomic, no matter if flag1 and flag2 are.
Now, if your function may modify the flags, and thus taking as a const reference being impossible, you don't have any other choice than to give the flags as two separate arguments and defer the evaluation inside the function.
From question comments again:
"The thing is, that function is usually called with one flag only, this is a special case in which I need two flags"
Considering this, you can overload the function to handle the cases with one or two parameters, something as follows:
int f(std::atomic<bool> & flag)
{
// ...
}
int f(std::atomic<bool> & flag1, std::atomic<bool> & flag2)
{
auto expr_result = flag1 && flag2; // Evaluation of the expression deferred into the function
// ...
}
The note above about the need of a synchronization mechanism (such as mutexes) if you want to make the evaluation of the expression atomic still applies here.
This question already has answers here:
Return statement in an infinite loop
(4 answers)
Closed 6 years ago.
I have a doubt as how return works in this case in C++. What happens to loops once condition matches and we need to return value.
some function(){
for( )//outer loop with i and other values
{
for( )// inner loop with i and other values {
some condition using if which on match return a value val (call it x here)
return x;
}
}
return -1
}
Nothing "happens" to the loops. Just like it always does, return returns from the function.
The loops evaporate into oblivion, just like any code following the return statement.
The only thing that "happens" is that your automatic-storage-duration objects (roughly speaking, your local variables) will be automatically destroyed.
The return statement, from any deepest if-statement, loop, or switch; will cause program control to return to the caller. It may return with a value, for a non-void function, or simply exit from the current function without any output for the caller.
Other than function, a return statement can be similarly used to exit from a lambda (since C++11). Semantics remain the same. Hence, if you see return statement inside a lambda (or multilevel nested lambda), they may not return from the function, but only from given lambda.
In both cases, locally declared variables will go out of scope, their memory (if held by some pointer) will be invalid. The destructors will be called (if allocated on stack).
You have nested for loops. However the function itself returns a constant value of -1. Perhaps you could be clearer in what you are asking
What does variable defintion do if I use it as the control structure of the if,while,for statements?
Consider these two fragments of code from C++ Primer(5th Edition):
while (int i = get_num()) //i is created and initialized on each iteration
cout << i << endl;
and
while(bool status = find(word)) {/*...*/} //assume that find(word) returns a bool type
I do not know whether variable definition "returns" a bool type to indicate the success of the definition,or variable definition returns the variable itself when used as the condition of control structure.
And I think the second fragment works fine,for status is the result of the
= operator.The condition tests whether status is true.
A friend of mine says the second fragment is in error,for the variable status is undeclared.
While loops expect a bool expression.
while({BOOL}) {...}
In the case of the code above
while(bool status = find(word)) {...}
simplifies down to
while(status) {...}
Status is initialized to the result of find(word) at the start of each execution of the loop.
status is then available within the loop.
ยง 3.3.3 Block Scope
Names declared in the for-init-statement, the for-range-declaration, and in the condition of if, while, for,
and switch statements are local to the if, while, for, or switch statement (including the controlled
statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost
block (or, for the if statement, any of the outermost blocks) of the controlled statement;
Regarding your second question:
do not know whether variable definition "returns" a bool type to indicate the success of the definition,or variable definition returns the variable itself when used as the condition of control structure.
As long as the variable is convertible to bool, there is no issue.
Given
while(Foo x = Expression()) {...}
can be expressed as
while(static_cast<bool>(x)) {...}
as long as Foo is convertible to bool, it can be declared and used in the while conditional.
The statements are both fine.
In the first case get_num() returns a value that is assigned to the newly declared variable i. ints are evaluated as true if they are not zero and evaluated as false if they are zero. So, this loop will run as long as i is not zero.
In the second statement find seems to return a bool which is assigned to status. As long as status is true, the loop will run.
Within the brackets of while the corresponding variable can be used, i.e. you can use i in the first loop and status in the second one, which really is the advantage of writing in like that. However, it does not really make sense in the second code snippet because you already know that status is true... otherwise the loop would just not be executed anymore. And if you change status here this does not work, either, because there will be a new locally declared status variable for each loop run.
In C++ the variable definitions became an operation, which they weren't in C up until that point. That change was made so that you could place the loop variable definition inside the for loop, e.g.
for (int i = 0; i < N; i++) {
printf("%d", i);
}
My question is what is the value of the variable definition operation, e.g. in which case what conditional statement will be executed in this example:
if (int i = N) {
printf("yes");
} else {
printf("no");
}
If the value of i after the initialization is not equal to zero then the if substetement will be executed. Otherwise the else substatement will be executed.
More precisely (the C++ Standard, 6.4 Selection statements)
4 The value of a condition that is an initialized declaration in a
statement other than a switch statement is the value of the declared
variable contextually converted to bool
And (4.12 Boolean conversions)
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
to member type can be converted to a prvalue of type bool. A zero
value, null pointer value, or null member pointer value is converted
to false; any other value is converted to true.
Consider a simple example
#include <iostream>
#include <cstring>
//...
char nickname[] = "mgn1993";
if ( char *p = std::strchr( nickname, 'm' ) ) *p = 'M';
std::cout << nickname << std::endl;
In this code fragment variable p is only needed inside the substatement of the if statement. There is no great sense to declare the variable in the outer scope.
You can use this as a shorthand for evaluating an expression, and use its return value inside the if block. e.g.
if (int i = calculateSomething()) {
// do something with i
}
which is equivalent to
int i = calculateSomething();
if (i) {
// do something with i
}
except that i's scope is restricted to the if block
The value of a variable definition is the variable itself.
int i = 0; // is 0, and is therefore false
int j = 5; // is 5, and is therefore true
The scope of a variable definition is the block it applies to.
So:
if(int i = returnSomething()) {
// This point is reached if returnSomething() did not return 0
// i is defined in this block and can be used.
}
// i is not defined at that point, its scope being limited to the if block above
In the provided example, the output would be "yes", if N has a non-zero value (which would evaluate to a boolean true in C++). There is no real value to the given example, as you can very easily substitute the entire assignment with 'N' and achieve the same effect.
Maybe there is some strange fringe case where we very much need to both use and be able to adjust the value contained in N ONLY if N is non-zero and we simultaneously need to be absolutely assured the scope is restricted to the if-statement, but this seems an unlikely scenario.
That said, declaring a variable for instance in a for loop certainly has its advantages. For starters the scope is limited to the loop, some compilers optimize specifically for it, potentially cleaner code, etc.
The following syntax is valid:
while (int i = get_data())
{
}
But the following is not:
do
{
} while (int i = get_data());
We can see why via the draft standard N4140 section 6.4:
1 [...]
condition:
expression
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list
2 The rules for conditions apply both to selection-statements and
to the for and while statements (6.5). [...]
and section 6.5
1 Iteration statements specify looping.
iteration-statement:
while ( condition ) statement
do statement while ( expression ) ;
Instead, you're forced to do something ugly like:
int i = get_data();
do
{
} while ((i = get_data())); // double parentheses sic
What is the rationale for this?
It seems like scoping would be the issue, what would be the scope of i declared in the while portion of a do while statement? It would seem rather unnatural to have a variable available within the loop when the declaration is actually below the loop itself. You don't have this issue with the other loops since the declarations comes before the body of the loop.
If we look at the draft C++ standard section [stmt.while]p2 we see that for the while statement that:
while (T t = x) statement
is equivalent to:
label:
{ // start of condition scope
T t = x;
if (t) {
statement
goto label;
}
} // end of condition scope
and:
The variable created in a condition is destroyed and created with each iteration of the loop.
How would we formulate this for the do while case?
and as cdhowie points out if we look at section [stmt.do]p2 it says (emphasis mine):
In the do statement the substatement is executed repeatedly until the
value of the expression becomes false. The test takes place after each
execution of the statement.
which means the body of the loop is evaluated before we would even reach the declaration.
While we could create an exception for this case it would violate our intuitive sense that in general the point of declaration for a name is after we see the complete declaration(with some exceptions for example class member variables) with unclear benefits. Point of declaration is covered in section 3.3.2.
There are several reasons for why it would be difficult to allow.
The language sticks to the general rule that everything should be declared above the point of usage. In this case the variable declared in do-while would be declared below its expected natural scope (the cycle body). Making this variable accessible inside the cycle would've required a special treatment for do-while cycles. Even though we know examples of such special treatment (e.g. in-class member function bodies can see all class members, including the ones declared below), there's probably not much practical sense in doing it for do-while cycles.
In case of do-while these special treatment rules would also require finding a meaningful way of handling initialization of variables declared in this fashion. Note that in C++ language the lifetime of such variable is limited to one iteration of the loop, i.e. the variable is created and destroyed on each iteration. That means that for do-while cycle the variable will always remain uninitialized, unless you introduce some rule that would somehow move the initialization to the beginning of the loop body. That would be quite confusing in my opinion.
It would be very unnatural to have a declaration of i after the block and to then be able to access it in the block. Declaration in for and while are nice short-hands that give limited-scope use to a variable that is needed in the loop logic.
Cleaner to do it this way:
int i;
do {
i = get_data();
// whatever you want to do with i;
} while (i != 0);
This is because everything else follows the practice of declaring variables before you use them, eg:
public static void main(String[] args){
// scope of args
}
for(int i=1; i<10; i++){
// scope of i
}
{
...
int somevar;
//begin scope of var
...
//end of scope of var
}
This is because things are parsed top down, and because following this convention keeps things intuitive, thus why you can declare a while(int var < 10) because the scope of that var will be the area inside the loop, after the declaration.
The do while doesn't make any sense to declare a variable because the scope would end at the same time it would be checked because that's when that block is finished.
Add this
#define do(cond) switch (cond) do default:
at the beginning of your code.
Now, you can write
do (int i = get_data())
{
// your code
} while ((i = get_data()));
It is important that this #define does not break the original syntax of the do keyword in do-while loop.
However, I admit that it is obscure.
Your first syntax is valid while the second is not.
However, your while loop will loop forever, even if your function get_data() returns 0.
Not sure if that's exactly what you want to happen.