Suryansh Singh
Suryansh Singh

Reputation: 1173

Why vector.size() - something can give segmentation fault?

In following code as expected for loop won't run(due to condition i<0-1) and nothing will be printed:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    for(int i=0; i < 0-1; i++){
        cout<<"Yes"<<endl;
    }
    return 0;
}

But when I do the following, vector size is printed 0 as expected. And so for loop should not print anything, just like the above case. But in fact something like this is giving me error like segmentation fault or SIGKILL after printing Yes multiple times(in online ide using C++ 14 gcc 6.3):

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> a;
    cout<<a.size()<<endl;
    for(int i=0;i<a.size()-1;i++){
        cout<<"Yes"<<endl;
    }
    return 0;
}

Other thing I noticed is that it works as expected if I replace a.size() - 1 with just a.size().

Upvotes: 1

Views: 1209

Answers (2)

Timmmm
Timmmm

Reputation: 96586

a.size() returns an unsigned integer. When you subtract 1 from unsigned 0 it underflows (look up "unsigned integer underflow" to 0xFFFFFFFF (a really big number). So your loop runs for a really long time.

In fact since all possible ints are less than 0xFFFFFFFF the compiler is smart enough to know that i<a.size()-1 will never be true, and it just turns the loop into an infinite loop.

You can verify this behaviour on Godbolt.

The following code:

#include <vector>
using namespace std;

void foo() {
    vector<int> a;
    for(int i=0;i<a.size()-1;i++){
        asm("");
    }
}

Is compiled to this assembly:

foo():                                # @foo()
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        jmp     .LBB0_1

Which is just an infinite loop. The asm("") is some magic so that the compiler doesn't remove the loop body.

Upvotes: 6

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122430

1 is an integer literal of type int, but std::vector<int>::size() returns an unsigned value.

A better comparison would be

#include <iostream>
#include <vector>

int main() {
    for(int i=0; i < 0u -1; i++){
        std::cout << "Yes" << std::endl;
    }
}

0u is an unsigned integer literal, and 0u -1 wraps around to a very large number. When you run this code you will see the same effect as with the vectors size.

One workaround is to add rather than subtract:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> a;
    std::cout << a.size() << std::endl;
    for(int i=0; i+1 < a.size(); i++){
        std::cout<< "Yes" << std::endl;
    }
}

Upvotes: 2

Related Questions