I have a simple question for optimizing my code.
bool myfunc();
if (false && true && myfunc())
{
}
Will the function myfunc() be called ??
Because C++ have short-circuit evaluation of conditions, no the function will not be called since the firstfalse makes the whole expression false anyway.
If you change the order, so you put the function call first (i.e. myfunc() && false && true) then the function will be called. The result of the expression will still be false though, no matter what myfunc returns.
No.
&& and || have short-circuit evaluation, that is, once the result is definitely known (false for && and true for ||) evaluation stops. And it's always strictly left-to-right.
In this case the compiler might even choose to elide the if statement completely, since the condition at compile-time is known to be false and thus the code afterwards is unreachable.
No, myfunc() will not be called, because of the first false, compiler will stop there. It's called short circuit evaluation.
Related
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.
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.
Today I found a syntax thing I had never seen before. Are || and , the same?
bool f() {
cout << "f";
return true;
}
bool g() {
cout << "g";
return true;
}
int main() {
if(f(),g())
{
cout<<"OK with ,";
}
cout<<endl;
if(f()||g())
{
cout<<"OK with ||";
}
return 0;
}
From the output of this program, it seems so:
fgOK with ,
fOK with ||
Are they the same exact thing or are there any little differences?
f(),g() means evaluate f() then evaluate g() and return g() since your g() returns true it is that what is returned to if
So, no, the operators are totally different.
You can see the difference if you modify your function to return false from g(). The condition f()||g() will still evaluate to true while f(),g() will return false.
This (comma operator)
if(f(),g())
will evaluate both f() and g() and return the value of the second operand g()
The logical OR operator
if(f()||g())
will not evaluate g() if f() evaluates to true. This is known as short-circuit evaluation - if f() returns true, then the logical OR condition is already satisfied - hence there is no point evaluating g().
So they are NOT the same at all even though under certain conditions you may see the same overall behaviour.
|| is the logical OR operator and by standard it follows short-circuit evaluation (i.e. it won't evaluate the second operand if the first already suffices to determine the entire logical expression)
, is the comma operator that evaluates both but just return the value of the second operand.
By the way you should be seeing something like:
fgOK with ,
fOK with ||
the reason why you're not seeing it might be because you're using a compiler that doesn't strictly follow the standards (I suspect MSVC..)
http://ideone.com/8dSFiY
They are completely different operators that serve completely different purposes.
The main difference is that:
The , operator (unless overloaded) will evaluate all of its arguments and return the last one, no matter what.
The || operator will evaluate all the arguments until it reaches the first trueish value and will not evaluate the rest.
This is also the reason why the output, you are claiming to receive, is wrong.
I understand what a double exclamation mark does (or I think I understand) but I am not sure how it is defined on a random object. For example in the code snippet below:
Assignment *a;
if (!getAssignment(query, a))
return false;
hasSolution = !!a;
if (!a)
return true;
How do I know what value will the double exclamation mark result in ? In other words does it always convert to true ? false ? or can you define a behavior for it such as executing a method to determine the result (how does the object know how to act in this situation) ? I am bit confused about this piece of code due to all these exclamation stuff going on.. Any explanation is appreciated.
Hope I was clear and thanks.
a is a pointer. In C++, nullptr is defined to be an invalid pointer. !pointer turns a nullptr pointer into true and a non nullptr pointer into false. !boolean turns true into false and false into true. It will always work.
!(!a) is a useful way to think of it.
Don't think of it as "double exclamation mark", think of it as two separate operators, one running on the result of the other.
For all primitive types, it will "work". !a is equivalent to a == 0, so !!a is equivalent to !(a == 0), which in turn is equivalent to a != 0.
For user-defined types, it won't compile unless they overload operator !. But obviously, in this case, the behaviour could be almost anything.
!! is not a single token in C++ and simply resolves to applying the ! operator twice.
As a is a pointer and not an object of class type the ! cannot be overloaded. It is defined to return true if a is a null pointer and false otherwise.
The second application of ! simply negates the result of the first !.
The expression !!a is equivalent to a != 0.
The code is horribly complicated. In reality, you want to test whether the getAssigment method is successful and whether the assigned pointer is non-null.
The code tests that, albeit in a convoluted fashion, taking advantage of weak typing, rather than trying to embrace explicitness and C++’ strong typing. As a consequence, it’s not idiomatic C++ and rather harder to understand than necessary.
In particular, don’t use !!a in C++. This is an established idiom in weakly-typed languages such as JavaScript to coerce a value into a boolean type. But in C++, this is not commonly used.
It’s not clear what the code does since hasSolution isn’t defined or used. However, I suspect that the code is supposed to be equivalent to the following:
Assignment *a;
return getAssignment(query, a) and a == nullptr;
(Before C++11, you need to write 0 instead of nullptr.)
However, this code still reveals a bad design: why is a passed by reference? Why isn’t it the return value? Worse, a is never used, so unnecessary. If a is indeed unnecessary, it should be left out completely. If it’s necessary, it should be the return value. In other words, the prototype of getAssignment should be as follows:
Assignment* getAssignment(the_type_of_query query);
And it should be used simply as follows:
Assignment* a = getAssignment(query);
Furthermore, I suspect that this code actually assigns memory ownership to the raw pointer a. This is strongly discouraged in modern C++. Either use no pointers or a smart pointer.
bool result = true;
result = !!result; // result = true, e.g. !result is false, !!result is !false.
There is no "!!" operator, so in fact, the statement is equivalent to:
hasSolution = !(!a);
So first, operator!() is called on expression "a", then another operator!() is called on the result. In the case of our code, "a" is a pointer to Assignement. C++ defines a special case for using operator!() on a pointer type: it returns a bool which is true if the pointer is null and false otherwise. In short, the same as the expression (a == 0). Calling operator!() on the result of (!a), which is a bool, simply reverts the result, i.e. returns true if (!a) is false and false if (!a) is true.
So in conclusion, (!!a) return the same result as (a != 0). This is because "a" is a pointer.
The easiest way to remember double-negation !!a is to narrow a!=0 to 1 and a==0 to 0.
Which is in boolean context (i.e. C++) true or false.
So can someone help me grasp all the (or most of the relevant) situations of an assignment inside something like an if(...) or while(...), etc?
What I mean is like:
if(a = b)
or
while(a = &c)
{
}
etc...
When will it evaluate as true, and when will it evaluate as false? Does this change at all depending on the types used in the assignment? What about when there are pointers involved?
Thanks.
In C++ an attribution evaluates to the value being attributed:
int c = 5; // evaluates to 5, as you can see if you print it out
float pi = CalculatePi(); // evaluates to the result
// of the call to the CalculatePi function
So, you statements:
if (a = b) { }
while (a = &c) { }
are roughly equivalent to:
a = b
if (b) { }
a = &c
while (&c) { }
which are the same as
a = b
if (a) { }
a = &c
while (a) { }
And what about those if (a) etc when they are not booleans? Well, if they are integers, 0 is false, the rest is true. This (one "zero" value -> false, the rest -> true) usually holds, but you should really refer to a C++ reference to be sure (however note that writting if (a == 0) is not much more difficult than if (!a), being much simpler to the reader).
Anyways, you should always avoid side-effects that obscure your code.
You should never need to do if (a = b): you can achieve exactly the same thing in other ways that are more clear and that won't look like a mistake (if I read a code like if (a = b) the first thing that comes to my mind is that the developper who wrote that made a mistake; the second, if I triple-check that it is correct, is that I hate him! :-)
Good luck
An assignment "operation" also returns a value. It is the type and value of the expression. If handled by an if type statement:
while (expr)
do ... until (expr)
if (expr)
or the ternary operator (expr) ? (true value) : false value
expr is evaluated. If it is nonzero, it is true. If zero, it is false.
The return type of the assignment is the left hand value, it's what allows statements like a = b = c to compile. In your example:
while(a = &c)
{
}
Returns true when "a" is true, after it has been assigned the value of &c.
In both examples you listed, inside the parentheses is evaluated to true if a is non-zero after the assignment.
In a more common case, you compare a variable with a constant, to avoid this problem, some coding standards require that you write the constant first.
if (A_CONSTANT = var_a)
this would be caught by the compiler, whereas,
if (var_a = A_CONSTANT)
won't.
An assignment statement evaluates to the new value of the variable assigned to (barring bizarre overloads of operator=). If the assignment happens in a boolean context it will then depend on the type of that value how it is treated. If the value is a bool, it is of course treated as a bool. If the value is a numeric value, a non-zero value is treated as true. If the value is a pointer, a non-NULL value is treated as true. If it is a object, the compiler will attempt to convert it to a boolean value (e.g. operator bool). If that is not possible, the compiler will attempt to convert the object to a value that is convertible to bool (e.g. a pointer type, or a numeric type such as int). Finally, if there is no conversion to be performed, or there are multiple possible conversions (e.g. the object defines operator int and operator foo*), the code will fail to compile.
if (a = b)
...
is the shorthand for:
a = b;
if (a != 0)
...
In a while statement, assignment within the condition enables the DRY principle:
while (a = b)
{
...
}
is shorthand for (notice how I had to replicate the assignment so that it is done right before the condition check):
a = b;
while (a != 0)
{
...
a = b;
}
That said, one classic issue with code like this is knowing whether the code intended to do an assignment or if the code forget an '=' when the intent was to write '==' (i.e. should that have been while (a == b).
Because of this, you should never write just a plain assignment (gcc will issue a warning such as "suggest parentheses around assignment used as truth value"). If you want to use assignment in a control structure, you should always surround it with extra parentheses and explicitly add the not-equal:
if ((a = b) != 0)
...
while ((a = b) != 0)
...