push_back does a bounds check. operator[] does not. So even if you’ve reserved the space, push_back is going to have an extra conditional check that operator[] will not have. Additionally, it will increase the size value (reserve only sets the capacity), so it will update that every time.
In short, push_back is doing more than what operator[] is doing – which is why it is slower (and more accurate).