Modern C++ is really a complicated but very fun language to use, IMO.
Working on an Advent of code problem 2022-day05, I ran into a common bug my compiler would have caught if I enabled the proper flags.
I wanted to iterate over my vector in reverse order. Initially I came up with the following code
for (size_t i = nums.size(); i >= 0; i--) {
std::cout << nums[i]; //
}
Looks innocent, however if you run this, you will get a segmentation fault error. Don't believe me, try it.
#include <iostream>
#include <vector>
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[])
{
std::vector<int> nums = { 1, 2, 3, 4, 5 };
for (size_t i = 0; i < nums.size(); ++i) {
std::cout << nums[i]; //
}
std::cout << std::endl;
// reverse
for (size_t i = nums.size() -1; i >= 0; i--) {
std::cout << nums[i];
}
std::cout << std::endl;
return EXIT_SUCCESS;
}
What is happening here, If I had the proper compiler flags and did not ignore them, we would see that the condition i >=0 always evaluates to true, causing an infinite loop. This is due to the fact that size_t is a unsigned type, which is always zero or more... A very common error... Opps!!!
g++ -Wextra
# warning: comparison of unsigned expression in ‘>= 0’ is always true [-Wtype-limits]
There are many ways we can fix this to iterate over a vector in reverse order.
A few solutions below
You can just use an int64_t ( or something that is not unsigned )
// reverse
for (int64_t i = nums.size()-1; i >= 0; i--) {
std::cout << nums[i];
}
std::cout << std::endl;
You can also just shorten this to
// reverse
for ( size_t i = nums.size( ); i--; ) {
std::cout << nums[i];
}
std::cout << std::endl;
The loop will stop once i reaches 0.
OR
we can use ranges in c++20
// reverse
for ( auto &&i : nums | std::views::reverse) {
std::cout << i; //
}
std::cout << std::endl;
This is awesome. Clean, easy to read IMO.
See more examples about reverse_view.
Hopefully I will learn some new things in c++20, especially with ranges now it seems stable.