Vector :: at vs. vector :: operator []

I know that at() slower than [] because of its bounds check, which is also discussed in similar issues such as the C ++ Vector at / [] speed operator or :: std :: vector :: at () vs operator [] <<amazing results! 5 to 10 times slower / faster! . I just don’t understand what the at() method is suitable for.

If I have a simple vector like this: std::vector<int> v(10); , and I decide to access its elements using at() instead of [] in a situation where I have an index i , and I'm not sure if it is within the boundaries of vectors, it forces me to wrap it with a try-catch block :

 try { v.at(i) = 2; } catch (std::out_of_range& oor) { ... } 

although I can do the same behavior using size() and check the index myself, which seems easier and more convenient for me:

 if (i < v.size()) v[i] = 2; 

So my question is:
Advantages of using vector :: at over vector :: operator [] ?
When should you use vector :: at rather than vector :: size + vector :: operator [] ?

+71
c ++ stl stdvector
Feb 21 2018-12-12T00:
source share
8 answers

I would say that the exceptions that vector::at() throw are not really intended to be caught immediately by the surrounding code. They are mainly useful for detecting errors in code. If you need to check the bounds at runtime, for example, the index comes from user input, you really do the best if . So, in short, create your code with the intention that vector::at() will never throw an exception, so if this happens and your program breaks, this is a sign of error. (just like assert() )

+58
Feb 21 '12 at 10:40
source share

it makes me wrap it with a try-catch block

No, this is not the case (the try / catch block may be upstream). This is useful if you want an exception to be thrown, not your program, to enter the undefined behavior area.

I agree that most of the non-access to vectors is a programmer's mistake (in this case, you should use assert to find these errors more easily; most debug versions of standard libraries do this automatically for you). You do not want to use exceptions that you can catch up to report programmer errors: you want to be able to fix the error .

Since it is unlikely that access beyond the limits of access to the vector is part of the normal flow of the program (if so, you are right: check size , instead of throwing an exception) I agree with your diagnosis: at is essentially useless.

+16
Feb 21 '12 at 10:40
source share

What are the benefits of using vector :: at over vector :: operator []? When should you use the vector :: instead, and not the vector :: size + vector :: operator []?

The important point here is that exceptions allow you to separate the normal code flow from the error processing logic, and one blocking block can handle problems that arise from any of the myriad throw sites, even if they are scattered inside function calls. So, it's not that at() necessarily easier for one use, but sometimes it gets easier - and less obfuscated normal logic - when you have a lot of indexing to check.

It should also be noted that in some types of code the index is incremented in complex ways and is constantly used to search for an array. In such cases, it is much easier to provide the correct checks with at() .

As a real-life example, I have code that tokens C ++ in lexical elements, and then another code that moves the index along the token vector. Depending on what happened, I can enlarge and check the following element, as in:

 if (token.at(i) == Token::Keyword_Enum) { ASSERT_EQ(tokens.at(++i), Token::Idn); if (tokens.at(++i) == Left_Brace) ... or whatever 

In such a situation, it is very difficult to check if you have not improperly reached the end of the input, because it is very dependent on the exact tokens. Explicit verification at each point of use is painful, and there is much more room for a programmer's error, since increments before / after, offsets at the point of use, erroneous discussions about the continued validity of some earlier tests, etc. Click.

+11
Feb 21 '12 at 10:43
source share

Firstly, is it not slower than at() or operator[] . when there are no errors in the boundaries, I expect that they will be approximately the same speed, at least in the debug builds. The difference is that at() indicates exactly what will happen as a result of a border error (exception), where, as in the case of operator[] , this is undefined behavior - a crash in all the systems that I use (g ++ and VC ++ ), at least when regular debug flags are used. (Another difference is that when I'm sure of my code, I can get a significant increase in speed for operator[] disabling debugging. If performance requires it, I would not do it if it were necessary.)

In practice, at() rarely suitable. If the context is such that you know that the index may be invalid, you probably need an explicit test (for example, returning the default value or something else), and if you know that this cannot be invalid, you want to abort ( and if you don’t know whether it can be invalid or not, I would suggest you specify the function interface more accurately). However, there are a few exceptions where an incorrect index can occur as a result of analyzing user data, and the error should cause the entire request to be interrupted (but not bring the server down); in such cases, an exception is appropriate, and at() will do this for you.

+5
Feb 21 2018-12-21T00:
source share

at may be clearer if you have a pointer to a vector:

 return pVector->at(n); return (*pVector)[n]; return pVector->operator[](n); 

Performance aside, the first one is simpler and more understandable code.

+4
Jul 23 2018-12-14T00:
source share

The whole point of using exceptions is that your error handling code can be removed.

In this particular case, user input is a really good example. Imagine that you want to semantically analyze an XML data structure that uses indexes to refer to some resource that you store inside std::vector . Now the XML tree is a tree, so you probably want to use recursion to parse it. In depth, in recursion, there may be an access violation by the writer of the XML file. In this case, you usually want to break out of all levels of recursion and simply reject the entire file (or any coarser structure). This is where it comes in handy. You can simply write the analysis code as if the file was valid. The library code will take care of detecting errors, and you can simply catch the error at a rough level.

In addition, other containers, such as std::map , also have std::map::at , which has slightly different semantics than std::map::operator[] : at can be used on the map const, and operator[] cannot. Now, if you want to write container agnostic code, for example, something that can deal with const std::vector<T>& or const std::map<std::size_t, T>& , ContainerType::at will be your weapon of choice.

However, all of these cases usually arise when processing some unapproved data entry. If you are confident in your valid range, as usual, you can usually use operator[] , but even better, iterators with begin() and end() .

+1
Feb 21 2018-12-21T00:
source share

According to this article, unlike performance, it makes no difference to use at or operator[] only if access is guaranteed to be within the size of the vector. Otherwise, if access is based only on the capacity of the vector, it is safer to use at .

0
Feb 22 2018-12-22T00:
source share

Note. It seems that some new people refuse to answer this question, not being able to say what is wrong. Below is the correct answer, which can be checked here .

In fact, there is only one difference: at performs border checking, and operator[] . This applies to both debug and release versions, and it is very well defined by standards. It is so simple.

This makes at a slower method, but its also very bad advice not to use at . You should look at absolute numbers, not relative numbers. I can safely argue that most of your code performs more expensive operations than at . Personally, I try to use at because I do not want an unpleasant mistake to create vague behavior and penetrate into production.

0
Jan 28 '18 at 3:10
source share



All Articles