The difference between c[i] and c.at(i) is that at() throws std::out_of_range exception if i falls outside the range of the vector, while operator[] simply invokes undefined behavior, which means anything can happen.

Nobody says at() is better than operator[] . It just depends on circumstances. As at() performs range check, it may not be desirable always, especially when your code itself makes sure that the index can never fall outside the range. In such cases, operator[] is better.

Consider the following loop:

for(size_t i = 0 ; i < v.size(); ++i) { //Should I use v[i] or v.at(i)? }

In such a loop, operator[] is always a better choice in comparison to at() member function.

I would prefer at() when I want it throw exception in case of invalid index, so that I could do the alternative work in the catch{ ...} block. Exceptions help you separate the normal code from the exceptional/alternative code as:

try { size_t i = get_index(); //I'm not sure if it returns a valid index! T item = v.at(i); //let it throw exception if i falls outside range //normal flow of code //... } catch(std::out_of_range const & e) { //alternative code }