Post incremeting in C++ vs adding 1 [duplicate] - c++

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 4 years ago.
test321["abc"] = 1;
test321["abc"] = test321.count("abc") ? test321["abc"]++ : 0;
test321["abc"] = 1
test321["abc"] = 1;
test321["abc"] = test321.count("abc") ? test321["abc"]+1 : 0;
test321["abc"] = 2
Why is there a difference?

The line
test321["abc"] = test321.count("abc") ? test321["abc"]++ : 0;
has undefined behavior until C++17 since test321["abc"] is modified in two ways:
By assignment.
By the post increment operator.
It's best to avoid using such constructs. You can read more about it at Why are these constructs (using ++) undefined behavior in C?.
The second approach is well-behaved code and should be used for what you intend to do.
If you use C++17, both approaches should result in identical behavior.

The question you're posing, "Why is there a difference?", is less meaningful than you might expect, because your code invokes Undefined Behavior.
Consider the following code snippet which is, semantically, equivalent to what your code is doing:
int x = 1;
x = x++;
What is a logical result for x? Is there a logical result?
Well, if you ask the C++ standard, the answer is that there is no logical result, and it leaves the result of an operation like this to be undefined. Any given compiler is given no restrictions or limitations on what it should do with code like this, so some compilers will work out that a logical result is for x to equal 2, and some compilers will work out 1 instead. Some compilers might (rarely) do something else entirely.
For more on this particular phenomenon, see this related Question.
To avoid undefined behavior, you should prefer constructs like this:
auto & ref = test321["abc"];//We save the reference to avoid performance issues
//Note that the brackets operator will create an entry if it doesn't already exist, negating
//the need for a check to count(); count() will always return at least 1.
ref = 1;
ref = ref + 1;
Or
if(auto & ref = test321["abc"])
ref++;//Will only increment if value was not 0.

Related

In C++, what does it mean when equals is used twice? [duplicate]

This question already has answers here:
double '=' in initialization
(3 answers)
Closed 3 years ago.
My apologies if this is a duplicate: searching for this isn't easy.
Example code taken from rtorrent:
m_bindings[KEY_UP] = m_bindings['P' - '#'] = std::bind(&ElementDownloadList::receive_prev, this);
What does the double value-setting mean, and how can this statement be explained?
The expression is evaluated from the right equals sign to the left. The statement a = b = c can be rewritten a = (b = c). The result of an = operation is the value that was assigned. Thus the result of (b = c) is c, making the next operation equivalent to a = c.
This is similar to x = y = 1 which is short hand for y = 1 and x = y.
This is called operator chaining. What you are doing is assigning the return value of the right hand operator = to the left hand operator =
It is equivalent to doing
m_bindings['P' - '#'] = std::bind(&ElementDownloadList::receive_prev, this);
m_bindings[KEY_UP] = m_bindings['P' - '#'];
but saves you a line of code. It also saves you from calling operator[] a second time, which could be expensive. Personally, I would use the 2 line version to make the code easier to read unless performance is really an issue.

Return value in C++ [duplicate]

This question already has answers here:
C++ return value without return statement
(6 answers)
Closed 6 years ago.
I am confused with the following output in C++
int add()
{
int c = 2+3;
}
int main()
{
int x = add();
cout << x;
return 0;
}
This prints 5.even if we do not write return statement.
How this is managed in C++.
Please help.
This is UB. You're right to be confused - this can work one day and fail the next. Don't rely on undefined behavior.
If you want to know why it works, it's because parameters & return values are passed on a data structure called stack (well - usually; sometimes passed in the same register). Similarly, most implementations use this same stack for locals. Therefore, the int in add will be located in the same place as where the return value is expected (by your specific implementation) and your implementation doesn't invalidate memory when your int there is destructed. But it's still destructed, it's still UB and it might break in any second.
As the comments wrote, you might turn on warnings to avoid this kind of error.

How does C++ process this [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 7 years ago.
I have here an equation i can't understand how c++ process this. Can someone explain this operation?
code:
#include <stdio.h>
main(){
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int i = 0;
int num = a[i+++a[++i]]+a[++i+i++];
printf("\nnum1: %d i: %d,num,i);
}
why is the answer num = 9 while index i is just equal to 4;
Using ++ twice in the same expression on the same variable is explicitly undefined by all versions of both the C and C++ standards, and so i does not necessarily equal 4. It could be anything at the whim of the compiler writer.
Never do this. Never use ++ and -- twice in the same expression. There is no way to make any statement about what the resultant value will be, and no experience with what it does with one compiler will mean anything with respect to what another compiler does.

Default value of dynamic bool array in C++ [duplicate]

This question already has answers here:
Does new[] call default constructor in C++?
(4 answers)
Closed 8 years ago.
I need to create a bool array with an unknown length passed by parameter. So, I have the following code:
void foo (int size) {
bool *boolArray = new bool[size];
for (int i = 0; i < size; i++) {
if (!boolArray[i]) {
cout << boolArray[i];
}
}
}
I thought that a boolean array was initializing with false values...
Then, if I run that code in Eclipse (on Ubuntu), it works fine for me, the function prints all the values because !boolArray[i] return true (but the values are not false values, they are garbage values). If I run it in Visual Studio, the values are garbage values too, but the function does not print any value (because !boolArray[i] returns false). Why the array values are not false values by default?!? And why !boolArray[i] returns false in Visual Studio but it returns true in Eclipse?!?
I read this question: Set default value of dynamic array, so if I change the code like the following, it works fine for me too (in Eclipse and in Visual Studio)! But I have no idea why.
void foo (int size) {
bool *boolArray = new bool[size]();
for (int i = 0; i < size; i++) {
if (!boolArray[i]) {
cout << boolArray[i];
}
}
}
Sorry for my bad English!
Thanks in advance!
Adding the () for a POD instantiation, invokes value initialization in C++03 and later. In C++98 it invoked default initialization. But both reduce to zero initialization for POD types, and for booleans zero is false.
E.g., if S is a POD struct, and you have a variable
S o;
then you can zero it by doing
o = S();
No need for unsafe and ugly memset.
By the way, std::vector<bool> is a higher level alternative to your raw array of bool, but due to what's now seen as premature optimization it has a bit odd behavior: it supports an implementation with each boolean value represented by a single bit, and so dereferencing an iterator doesn't give you a reference to a bool as one might expect from general std::vector. So a better alternative is e.g. std::vector<My_bool_enum>, with My_bool_enum properly defined. Or just std::vector<char>. ;-)
Regarding
“And why !boolArray[i] returns false in Visual Studio but it returns true in Eclipse?!?”
It's just that Visual C++ chooses efficiency, not initializing where it doesn't have to, while the compiler used in Eclipse (presumably g++) does initialize even though it doesn't have to and isn't requested to do.
I prefer the Visual C++ behavior here for two reasons:
A main idea in C++ is that you don't pay for what you don't use, and the Visual C++ behavior here is in line with that idea.
Zero-initialization can easily give users the false impression that their code works, when in fact it's not portable.

*buf++ = *buf + 10 - Explanation [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 9 years ago.
Example code
int arr[3] = { 0, 1 };
int* buf = arr;
*buf++ = *buf + 10;
Result of last expression is that buf[0] == 10. I taught it would be buf[0] == 11.
A college of mine wrote something similar to the example code and I taught it works differently than it does. And I would like to know why it works the way it does.
The way I went about figuring it out was to look at the operator precedence table. There it states that suffix ++ has precedence over dereference. Hence I taught that on the left of operator= buf would point to the first element, but on the right of the operator= it would have already been incremented and would point to the second element. However that is not the case.
My question is, why is that so? Preferably a standard quote :) However any explanation is welcome!
You are accessing and modifying the pointer multiple times in a single sequence point. This is undefined behavior.
More generally, reading from and writing to any variable between sequence points is undefined. The fact that you have a pointer in this specific example is by-the-by.
To avoid confusion with the pointer:
int i = 0;
i++ = i + 1; // UB
Logically, should the i on the right hand side be the "current" value of i, or the modified value? This is why it is undefined. Instead, separate the code:
int i = 0;
++i;
i = i + 1;
Which is clear, and well defined.