I am trying use auto to infer the type.
for (auto i = remaining_group.size() - 1; i >= 0; --i) {
std::cout << i;
}
I get very large number like 18446744073709534800 which is not expected. When I change auto to int it is the number I expected between 0 and 39.
Is there any reason auto will fail here?
remaining_group's type is a std::vector<lidar_point> and lidar_point is struct like:
struct LidarPoint {
float x;
float y;
float z;
uint8_t field1;
double field2;
uint8_t field3;
uint16_t field4;
}
When using auto the type of i would be std::vector::size_type, which is an unsigned integer type. That means the condition i >= 0; would be always true, and if overflow happens you'll get some large numbers.
Unsigned integer arithmetic is always performed modulo 2n
where n is the number of bits in that particular integer. E.g. for unsigned int, adding one to UINT_MAX gives 0, and subtracting one from 0 gives UINT_MAX.
Simple reproduction of problem:
#include <iostream>
size_t size() {return 1;}
int main() {
for (auto i = size() - 1; i >= 0; --i) {
std::cout << i << std::endl;
}
}
size() got type size_t and literal constant 1 would be promoted to size_t, in result auto would become size_t, which cannot be less than zero, resulting in infinite loop and underflow of i.
If you need a reverse index loop, use operator -->
When you write a normal index loop, you write it with 0, size, and <.
When you write a normal reverse index loop, things become a bit wonky: you need size - 1, >=, 0, and you can't use unsigned index, because unsigned i is always >= 0 so your check i >= 0 always returns true, your loop could run forever.
With fake operator "goes to", you can use 0, size, and > to write the reverse index loop, and it doesn't matter if i is signed or unsigned:
for (auto i = a.size(); i --> 0; ) //or just i--, or i --> 1, i --> 10...
std::cout << i << ' ';
Related
While debugging my code I have noticed that something strange is going on, So I have added more lines and got confused even more:
#include <iostream>
#include <memory>
struct Node
{
size_t size = 0;
};
class MallocMetadata {
public:
size_t size; /** Effective allocation - requested size **/
bool is_free;
MallocMetadata *next;
MallocMetadata *prev;
MallocMetadata *next_free;
MallocMetadata *prev_free;
};
int main()
{
size_t size = 0;
auto node = std::make_shared<Node>();
int tmp_res=node->size - size - sizeof(MallocMetadata);
bool test=(node->size - size - sizeof(MallocMetadata)) < 128;
bool test1=tmp_res<128;
std::cout << tmp_res << "\n";
std::cout << test << "\n";
std::cout << test1 << "\n";
}
After running these 3 lines I saw:
tmp_res=-48
test = false
test1 = true
How is this even possible! why test is false, -48 is smaller than 128
Here's a proof:
It looks like the part node->size - size - sizeof(MallocMetadata) is calculated in unsigned integer.
When calculation of unsigned integer is going to be negative, the maximum number of the type plus one is added and the result wraparounds.
Therefore, the value looks like being big value (128 or more), making the expression (node->size - size - sizeof(MallocMetadata)) < 128 false.
In the other hands, int tmp_res=node->size - size - sizeof(MallocMetadata); will convert the big value to int. int is signed and it may give different value than the expression above that doesn't perform convertion to int.
I believe whenever there is an unsigned value in an expression, the result tends to be unsigned aswell.
size_t size = 0;
auto val = 1 + 100 + (-100) + size;
std::cout << typeid(val).name();
'val' will be a size_t aswell. So in your case, you're trying to store a negative value in size_t which causes overflow.
You can explicitly typecast it to a signed integer and that should be enough if I'm not mistaken.Like so:
bool test=int(node->size - size - sizeof(MallocMetadata)) < 128;
Please take a look at this simple program:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> a;
std::cout << "vector size " << a.size() << std::endl;
int b = -1;
if (b < a.size())
std::cout << "Less";
else
std::cout << "Greater";
return 0;
}
I'm confused by the fact that it outputs "Greater" despite it's obvious that -1 is less than 0. I understand that size method returns unsigned value but comparison is still applied to -1 and 0. So what's going on? can anyone explain this?
Because the size of a vector is an unsigned integral type. You are comparing an unsigned type with a signed one, and the two's complement negative signed integer is being promoted to unsigned. That corresponds to a large unsigned value.
This code sample shows the same behaviour that you are seeing:
#include <iostream>
int main()
{
std::cout << std::boolalpha;
unsigned int a = 0;
int b = -1;
std::cout << (b < a) << "\n";
}
output:
false
The signature for vector::size() is:
size_type size() const noexcept;
size_type is an unsigned integral type. When comparing an unsigned and a signed integer, the signed one is promoted to unsigned. Here, -1 is negative so it rolls over, effectively yielding the maximal representable value of the size_type type. Hence it will compare as greater than zero.
-1 unsigned is a higher value than zero because the high bit is set to indicate that it's negative but unsigned comparison uses this bit to expand the range of representable numbers so it's no longer used as a sign bit. The comparison is done as (unsigned int)-1 < 0 which is false.
Please take a look at this simple program:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> a;
std::cout << "vector size " << a.size() << std::endl;
int b = -1;
if (b < a.size())
std::cout << "Less";
else
std::cout << "Greater";
return 0;
}
I'm confused by the fact that it outputs "Greater" despite it's obvious that -1 is less than 0. I understand that size method returns unsigned value but comparison is still applied to -1 and 0. So what's going on? can anyone explain this?
Because the size of a vector is an unsigned integral type. You are comparing an unsigned type with a signed one, and the two's complement negative signed integer is being promoted to unsigned. That corresponds to a large unsigned value.
This code sample shows the same behaviour that you are seeing:
#include <iostream>
int main()
{
std::cout << std::boolalpha;
unsigned int a = 0;
int b = -1;
std::cout << (b < a) << "\n";
}
output:
false
The signature for vector::size() is:
size_type size() const noexcept;
size_type is an unsigned integral type. When comparing an unsigned and a signed integer, the signed one is promoted to unsigned. Here, -1 is negative so it rolls over, effectively yielding the maximal representable value of the size_type type. Hence it will compare as greater than zero.
-1 unsigned is a higher value than zero because the high bit is set to indicate that it's negative but unsigned comparison uses this bit to expand the range of representable numbers so it's no longer used as a sign bit. The comparison is done as (unsigned int)-1 < 0 which is false.
vector<int> function(vector<int> &arr)
{
for(auto i = arr.size() - 1; i >= 0; i--)
std::cout << arr[i] << " ";
return arr;
}
int main()
{
vector<int> arr{1,2,3,4};
function(arr);
}
Why does the above program cycle?
if I change auto with int everything is ok
arr.size() is an unsigned data type, usually size_t. With i being unsigned, i >= 0 is always true. Subtracting 1 from an unsigned variable that is 0 results in the biggest amount that the type can hold. As a result, it will cycle forever.
What then happens is uncertain, since your array index will turn into a gigantic value, and arr[i] will have undefined behavior for values >= arr.size(). If you have an int instead of auto, it works because the i-- will cause it to eventually be -1 and then i >= 0 will be false, exiting the loop.
An explanation of this rollover behavior can be found here:
Unsigned integer arithmetic is always performed modulo 2n where n is the number of bits in that particular integer. E.g. for unsigned int, adding one to UINT_MAX gives 0, and subtracting one from 0 gives UINT_MAX.
So, for size_t, subtracting 1 from 0 results in SIZE_MAX, which commonly has a value of 18446744073709551615.
What is you problem was already answered by Blaze and rafix07, but I wanted to add that in modern C++ its better to use iterators whenever possible. This has few advantages including code portability, better performance and more readable code.
Your code can look something like this:
std::vector<int> function(std::vector<int> &arr)
{
for(auto it = arr.rbegin(); i != arr.rend(); ++i)
std::cout << *it << " ";
return arr;
}
or like this
std::vector<int> function(std::vector<int> &arr)
{
std::for_each(arr.rbegin(), arr.rend(), [](int val) {
std::cout << val << " ";
});
return arr;
}
or even like this
std::vector<int> function(std::vector<int> &arr)
{
std::copy(arr.rbegin(), arr.rend(), std::ostream_iterator<int>(std::cout, " "));
return arr;
}
When you have a loop that goes the other way ( from max to 0 ) then you usually have this problem:
Either the max is size_t so i >= 0 is always true
Or you change i to int so you have a comparison of a signed with an unsigned which would result in a compiler warning, or a comparison of an int to a larger size_t in x64.
Redesign the loop:
Use a new type for i which would be long in x86 and long long in x64, now i >= 0 is good when your objects are not above 2^63 in x64 (most likely).
when i == 0, break inside the loop.
Change to the normal i = 0 and i < obj.size() method.
Couldn't you initialize an unsigned int and then increment it until it doesn't increment anymore? That's what I tried to do and I got a runtime error "Timeout." Any idea why this doesn't work? Any idea how to do it correctly?
#include
int main() {
unsigned int i(0), j(1);
while (i != j) {
++i;
++j;
}
std::cout << i;
return 0;
}
Unsigned arithmetic is defined as modulo 2^n in C++ (where n is
the number of bits). So when you increment the maximum value,
you get 0.
Because of this, the simplest way to get the maximum value is to
use -1:
unsigned int i = -1;
std::cout << i;
(If the compiler gives you a warning, and this bothers you, you
can use 0U - 1, or initialize with 0, and then decrement.)
Since i will never be equal to j, you have an infinite loop.
Additionally, this is a very inefficient method for determining the maximum value of an unsigned int. numeric_limits gives you the result without looping for 2^(16, 32, 64, or however many bits are in your unsigned int) iterations. If you didn't want to do that, you could write a much smaller loop:
unsigned int shifts = sizeof(unsigned int) * 8; // or CHAR_BITS
unsigned int maximum_value = 1;
for (int i = 1; i < shifts; ++i)
{
maximum_value <<= 1;
++maximum_value;
}
Or simply do
unsigned int maximum = (unsigned int)-1;
i will always be different than j, so you have entered an endless loop. If you want to take this approach, your code should look like this:
unsigned int i(0), j(1);
while (i < j) {
++i;
++j;
}
std::cout << i;
return 0;
Notice I changed it to while (i<j). Once j overflows i will be greater than j.
When an overflow happens, the value doesn't just stay at the highest, it wraps back abound to the lowest possible number.
i and j will be never equal to each other. When an unsigned integral value achieves its maximum adding to it 1 will result in that the next value will be the minimum that is 0.
For example if to consider unsigned char then its maximum is 255. After adding 1 you will get 0.
So your loop is infinite.
I assume you're trying to find the maximum limit that an unsigned integer can store (which is 65,535 in decimal). The reason that the program will time out is because when the int hits the maximum value it can store, it "Goes off the end." The next time j increments, it will be 65,535; i will be 0.
This means that the way you're going about it, i would NEVER equal j, and the loop would run indefinitely. If you changed it to what Damien has, you'd have i == 65,535; j equal to 0.
Couldn't you initialize an unsigned int and then increment it until it doesn't increment anymore?
No. Unsigned arithmetic is modular, so it wraps around to zero after the maximum value. You can carry on incrementing it forever, as your loop does.
Any idea how to do it correctly?
unsigned int max = -1; // or
unsigned int max = std::numeric_limits<unsigned int>::max();
or, if you want to use a loop to calculate it, change your condition to (j != 0) or (i < j) to stop when j wraps. Since i is one behind j, that will contain the maximum value. Note that this might not work for signed types - they give undefined behaviour when they overflow.