22

C++'s container vector, deque, ... provide the at(index) accessor function in addition to operator[index] to access container elements.

The difference between this member function and member operator function operator[] is that deque::at signals if the requested position is out of range by throwing an out_of_range exception.

I have never, ever needed this function in my code, as it never makes sense in my C++ code to access elements that are possibly out-of-range. The code is always written to access correct indexes (or produce a meaningful error/exception in case indexes can't be made to match.)

I would be interested in real world examples (possibly from some open source project, as that would add some context) where at() is used in production code.

Maybe someone can give an example of an algorithmic problem where using at() made sense.

Note: I have recently used it in some unit-test code, where adding index checking code wasn't considered worth the trouble and the out_of_range exception thrown by at() is considered enough info+context in case the test breaks.

Note: Regarding this answer by ildjarn - I do not want to start a discussion or comment war on this. I am interesting in "positive" finds, that is concrete examples where it has been used. Thank you.

Community
  • 1
  • 1
Martin Ba
  • 37,187
  • 33
  • 183
  • 337

8 Answers8

13

Well, when you don't control the index being used (such as if it's passed in by a client of your code), you should either check it to see if it's in range manually, or use at to get an exception reported (which you can capture and notify the caller with your own error reporting or simply propagate the standard exception upwards).

In other words, it's the responsibility of the called function to check input parameters but whether it does this explicitly with an if statement or implicitly by using at instead of [] is a matter for debate. If all I'm going to do is throw an out_of_range exception anyway (if the passed in index is greater than or equal to the size of the collection), I think I'll just let at do it and save myself some coding.

Passing back bad data silently is almost never the best solution. The trouble with simply passing back x[7] for a four-element integer deck is that the caller thinks it's a valid zero. That's not the case.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 3
    Input validation based on exception handling is a bad idea I think. Always check explicitly. – musiKk Apr 13 '11 at 07:29
  • @musiKk : Agreed; invalid input is an *expected* circumstance, not an exceptional one. – ildjarn Apr 13 '11 at 07:34
  • 5
    I have to disagree with that, @musiKk. Validation is validation whether it's checked in your code or thrown from lower levels. I don't ignore exceptions from file operations then manually check the status flags after every operation - it's far easier just to catch ios_base::failure and isolate the error handling to the `catch` bit. – paxdiablo Apr 13 '11 at 07:38
  • @paxdiablo : Throwing a potentially unhandled exception is **not** validation. And wrapping code in a `try{}catch{}` is **not** easier than checking the bounds of a container. When "easy" conflicts with "correct", I prefer to side with correctness. – ildjarn Apr 13 '11 at 07:45
  • @paxdiablo: Yes, but IO errors are not (input) validation. They are uncheckable (disk failing or full or whatever). Anyway, I'm a Java developer and in those circles programming by exception is usually frowned upon. I don't know enough about the idioms of C++. YMMV. – musiKk Apr 13 '11 at 07:47
  • 1
    @paxdiablo: Thanks for the general case, but note that your answer *fails* to provide a real-world usage *example* where you have seen it used or used it yourself. Have you ever used `at()` yourself to do input validation? – Martin Ba Apr 13 '11 at 08:02
  • 1
    @ildjarn: "throwing a potentially unhandled exception" - since when is the correctness of the caller a concern for the callee? If the callee is documented to throw, the caller needs to deal with it. – MSalters Apr 13 '11 at 14:30
  • @MSalters : And if the callee is documented to exhibit undefined behavior when given invalid input, the caller needs to deal with it. I'm not sure what you're getting at. I said throwing doesn't make anything *easier*, and it doesn't, because the caller needs to deal with it either way. – ildjarn Apr 13 '11 at 19:55
  • 1
    @ildjarn: I responded specifically to the bit that I quoted. It's a misleading comment because it suggests that the callee is somehow obliged to take bugs in the caller into account. – MSalters Apr 13 '11 at 22:26
  • @MSalters : I agree with that statement, as you've worded it. So how is throwing an exception when the caller passes an out-of-range value not doing exactly that, when the rest of the class has proper bounds access as a precondition? To me, that sounds *exactly* like the callee taking the caller's bugs into account. – ildjarn Apr 13 '11 at 22:29
  • @ildjarn: Obviously, the caller has to deal with the exception, so you're not taking bugs into account. The theory is that exception handling can be concentrated in one place up the stack, where bounds checking would be all over the place. You still have to deal with it. But this does lead to the question: does the theory work out in practice. – MSalters Apr 14 '11 at 07:45
7

In my opinion, at() is a 100% useless member function. Accessing only within the valid bounds of a standard library container is a precondition of using that container, and violations of any precondition should be handled with an assert rather than by throwing an exception. The existence of at() in no way helps a container maintain its preconditions/invariants, and in fact only confuses the issue by making proper bounds-checked access appear to not be a precondition.

I.e., throwing an exception for something that can ultimately only be caused by programmer error is beyond silly. See this thread for a more detailed explanation, specifically the posts by D. Abrahams; long though it may be, it's absolutely worth the read: comp.lang.c++.moderated: Exceptions.

EDIT: To clarify in response to the OP's added note, I'm saying that in my experience with C++ -- professionally, open-source, and otherwise -- I've never come across a use of standard containers' at(), and maintain that it is in fact not used in production code. Further comments or elaboration were merely to rationalize why I think that's the case.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
  • 1
    assert is a bad idea here simply because it's not usually active in production code and, on top of that, you _don't_ want your code exiting badly in a production environment. By all means handle it explicitly if you want (it's not necessary but I understand your viewpoint in doing it) but your users are going to crucify you if they lose data because of your assertion. – paxdiablo Apr 13 '11 at 07:41
  • 1
    @paxdiablo : That implies you find it acceptable and expected for obvious programmer errors to enter production code. I hold *my* code to higher standards at least... ;-] Point being, going out of bounds of a standard container class is simply using the type incorrectly; using a type incorrectly is **not** exceptional, it is something that *should/must* be caught before code goes into production. Again, read the thread I linked, as it articulates my opinion much better than I could. – ildjarn Apr 13 '11 at 07:43
  • 2
    My point is that you don't _know_ the ultimate source of the data coming into your function. It may be something the programmer got wrong, it may be a off-by-one error or there are many other reasons which should be caught by the programmer. There are also many other sources that the programmer has no control over (user, file, etc). However, the incompetence of the programmer using your code in no way absolves you of the responsibility of making your own code bulletproof. Whether that's done with checking or exception, I don't really care. But I don't think asserts are the answer here. – paxdiablo Apr 13 '11 at 07:48
  • @paxdiablo : If the *programmer* (i.e., you and I) uses `assert`s properly, there's no way 'something the programmer got wrong' or 'an off-by-one error' could get into production code code in the first place, assuming the programmer *ever* debugs their own code (and I surely *hope* they do). That's the whole **point** of `assert`. – ildjarn Apr 13 '11 at 07:49
  • Yes, I agree with that. But, as I stated, there are other reasons why thy information could be wrong. – paxdiablo Apr 13 '11 at 07:51
  • @paxdiablo : Give a **single** reason aside from programmer error or memory corruption that could cause code to read/write out of bounds on a standard container and I'll be happy to delete my answer. ;-] (Note: in the case of memory corruption, exceptions surely won't help.) – ildjarn Apr 13 '11 at 07:52
  • @ildjam Not sure I understand your point. Asserts have been turned on in most of the production code I've seen. About the only time you turn them off is if the profiler tells you to. And if there is a real error in the code somewhere, the only thing you can reasonable do is abort. – James Kanze Apr 13 '11 at 07:57
  • 1
    On the whole assert thing: we use an assert macro that raises an exception because then precondition failures won't terminate our unit test suite prematurely. Frankly `assert` is probably bad practice anyway - simply put, by using assert you assume you'll catch every bug that could lead to an assertion failure before release. Not likely. In a release build you need to ensure that an assertion failure causes your program to exit as gracefully as possible. – Adam Bowen Apr 13 '11 at 07:57
  • @James Kanze : The issue (in my mind) is handling preconditions vs. postconditions, and the proper way to do so. Going out of bounds on a standard container violates one of the container's preconditions and thus should be dealt with using `assert`. Beyond that, I can only refer you to the posts by D. Abrahams that I linked to in my answer. – ildjarn Apr 13 '11 at 08:00
  • @ildjam, I don't _want_ you to delete your answer. I disagree with the "useless" bit and I don't consider asserts a good idea but the idea of using precondition checking is not a bad one. As to an example, let's say you maintain a 10-element deque in your class and a program asks the user which element they want to view. If the user enters 15, it's debatable whether the program should check the value before passing it to you. In my opinion, it should, but that still wouldn't absolve me of checking it either with `if` or an `at` exception. I never assume that my clients know what they're doing. – paxdiablo Apr 13 '11 at 08:02
  • In other words, I program defensively at run time as well as debug and compile time. – paxdiablo Apr 13 '11 at 08:02
  • @paxdiablo : IMO, that example is a matter of documentation; if the class is *documented* to only maintain 10 elements, then the 10-element maximum is a precondition of the class and passing in a higher number is a violation of that, yielding UB (or an `assert`). If the class then documents that an exception will be thrown upon passing in a higher number, it becomes a postcondition. If it's a precondition, then it's the class consumer's responsibility to maintain proper bounds; if it's a postcondition then it's the class' responsibility. (Cont'd in another comment due to length restriction) – ildjarn Apr 13 '11 at 08:05
  • @paxdiablo : In the case of standard containers, `at()` is useless because it only displaces the precondition of a container's proper range/bounds for `operator[]` but not for any other functionality (like `begin() + N` or `std::advance(beginIter(), N)`). Because the function cannot entirely change the precondition into a postcondition, then it's useless by definition. – ildjarn Apr 13 '11 at 08:07
  • 4
    I'm going to leave the discussion here since it's noising up the issue. My final point is simply that you should never assume your caller is passing valid data. Period. I'll shut up now :-) – paxdiablo Apr 13 '11 at 08:08
  • 2
    @paxdiablo : **That** much we can certainly agree on, if not how to deal with invalid data. ;-D – ildjarn Apr 13 '11 at 08:09
  • @ildjam Which is what I said. Violation of a precondition is a real error in the code elsewhere. The correct response will depend somewhat on the application, but most of the time, aborting is the safest bet. – James Kanze Apr 13 '11 at 08:18
  • @James Kanze : Right. Which is the domain of `assert` and testing, not exceptions. – ildjarn Apr 13 '11 at 08:19
  • "in fact only confuses the issue by making proper bounds-checked access appear to not be a precondition". That's not true. It confuses the issue by making proper bounds-checked access *actually* not a precondition of the `at()` function. It is still a precondition of `operator[]`. You clearly *want* that precondition, which is why you don't use `at()`, but as far as C++ is concerned, violating preconditions results in undefined behavior, so `vector().at(0)` is not a violation of preconditions. It's guaranteed to throw an exception, just like `throw std::exception()` is. – Steve Jessop Apr 13 '11 at 08:46
  • @Steve Jessop : Right. The `at()` function having different preconditions than the rest of the container and its iterators *is* the confusing part. ;-P Again, I linked to the thread I linked to simply because it articulates my viewpoint better than I am capable of. – ildjarn Apr 13 '11 at 08:47
  • 7
    @ildjarn: I agree it's confusing, although only very slightly, C++ programmers need to be clever enough to remember these kinds of oddities. It's then a matter of coding style whether you choose to throw exceptions in situations where you can't access your vector because you don't have an in-bounds index. It's not morally finer, nor more maintainable, nor simpler, to write `if ((i >= 0) and (i < vec.size()) return vec[i]; else throw out_of_rage();` than to write `return vec.at(i);`. So *if* you want an exception anyway, `at` is useful. If you don't, it isn't. – Steve Jessop Apr 13 '11 at 08:51
  • @Steve Jessop : Fair enough, and clearly enough worded to warrant an answer of its own I think. :-] That said, the standard can't forsee every use or misuse of its classes, so it's strange to me that it attempts to forsee this one (which I've *never* had occasion to use). – ildjarn Apr 13 '11 at 08:54
  • @ldjarn: to address your point about `assert` - I'm not saying much if I say we can't assert that a real human user (or other form of input) has entered an in-bounds value. So somewhere between user input and accessing a container, someone is going to check that the value is in-bounds, and with a "real" check, not an assert. `at` places that check at the last possible moment before access, which is sometimes appropriate and sometimes totally inappropriate. It's a question of what bit of code assumes that responsibility, and how far up the API stack the container size is exposed. – Steve Jessop Apr 13 '11 at 08:58
  • @ldjarn: the reason I dived into comments rather than answering is that the OP has edited to say that he doesn't want answers to be general discussions, he wants concrete examples of use. Although I don't reject it in principle, in practice I never use `at()` either so I don't have examples to hand :-) – Steve Jessop Apr 13 '11 at 09:01
  • @Steve Jessop : "*It's a question of what bit of code assumes that responsibility.*" Right, which is the distinction between a precondition and a postcondition, and consequently the difference between using `assert` or an exception (respectively). I agree that **someone** has to do bounds-checking, I never said otherwise; I simply said that as the standard containers are defined in every respect *other than* `at()`, it's clear that it's up to we consumers of the standard containers to do it. – ildjarn Apr 13 '11 at 09:02
  • 1
    @Steve Your code is checking at the wrong time. If the programmer has control over the index, no check is needed, ever (apart from precondition checking; otherwise there’s a *bug* in the code). If the input is from somewhere else (user …) then it needs to be validated on a much higher level – namely, on the user interaction level, before it has any chance even coming near a container. A `throw` from inside a container takes place on a whole ’nother level. Code such as yours (`if (invalid(i)) throw out_of_bounds(); else return vec[i];`) contains a check/access adjacency that can never occur. – Konrad Rudolph Apr 13 '11 at 09:04
  • @ildjarn: Agreed, it's our responsibility, but for example `vector::at()` and `map::operator[]` are helper functions that handle out-of-bounds (in very different ways for the two of them, of course). Formally they're both superfluous, as is for example `vector::push_back`, since they're all defined to be equivalent to things you could do without them. I suppose `vector` could go further, and provide `iterator::checked_add`, but the difference there is that `at` is trivial to implement, whereas `checked_add` potentially has an implementation cost even if it's not actually used. – Steve Jessop Apr 13 '11 at 09:07
  • @Konrad: So you're saying that the size of the container *must* be exposed through all API levels up to the point of user-interaction? I claim that's a style decision, it's not possible to know that all code would be better-designed if that were the case. You're welcome to do that, but I think it would be daft to attempt to design the C++ language to enforce it, so your style has no bearing on whether `at` should exist (or, in general, whether it's reasonable to have parameterized accessor API's that throw exceptions for impossible values). – Steve Jessop Apr 13 '11 at 09:10
  • @Steve Jessop : "*So you're saying that the size of the container must be exposed through all API levels up to the point of user-interaction?*" No, but the idea that the user would give invalid input is *expected*, not exceptional, and thus throwing an exception is not appropriate. This of course delves into a tangent discussion on when using exceptions *is* appropriate, but it's probably clear from this duscission where I stand on that... ;-] – ildjarn Apr 13 '11 at 09:11
  • 1
    @ildjarn: "the idea that the user would give invalid input is expected, not exceptional, and thus throwing an exception is not appropriate" - That's coding style again. C++ is a multi-*paradigm* language, it certainly must tolerate multiple coding styles. Consider that C doesn't have exceptions at all, so *all* kinds of failure are expected. What means that in C, running out of memory is an "expected failure", whereas in C++ or Java, it's "exceptional"? Coding style, nothing else. – Steve Jessop Apr 13 '11 at 09:13
  • @Steve Jessop : That much I acknowledged in the very next sentence. But then, I started my whole answer off with "In my opinion"... – ildjarn Apr 13 '11 at 09:14
  • @ildjarn: right, I guess I'm basically saying that you should say, "in my opinion, I will never find a use for `at()`". Saying "in my opinion, at() is 100% useless" conveys to me that your opinion is that *nobody* will ever find a (good) use for `at()`. Konrad said basically as much to me - as soon as he saw that I was checking the bound adjacent to the access, he "knew" that my code was flawed, without knowing anything else about it. But perhaps I've split a hair the wrong way. – Steve Jessop Apr 13 '11 at 09:17
  • @Steve Jessop : Then I'll rephrase succinctly: In my *experience*, no one ever *has* found a good use for `at()`, and so it is *probably* useless. ;-] – ildjarn Apr 13 '11 at 09:19
  • 1
    @Steve I’m saying that user input must be sanitised on the spot. No more, no less. This is essentially the single most important task of the UI layer. That doesn’t require exposing any container details at all, it could also take place by exposing an `is_valid_index` method or similar. “I claim that's a style decision” – I claim that it isn’t, as far as “style” implies “subjective”. It’s a question that is long resolved and has a very much established best solution. – Konrad Rudolph Apr 13 '11 at 09:23
  • @ildjarn: fair enough :-). I think using `at()` exclusively, in preference to `operator[]`, would be a quite reasonable style. It's no different from the style used by most Java programmers when accessing their containers. In Java you still code to avoid ever actually throwing that exception from `Vector.get`, so in an ideal world it makes no difference. In the real world, the more information you get when a bug occurs, the better. I don't think I know any C++ programmers who actually use that style, though, we love operator syntax too much. Maybe whoever invented `at` - Stepanov? Stroustrup? – Steve Jessop Apr 13 '11 at 09:25
  • @Konrad: I think you're wrong, both about established best practice and about what UI layers actually do in practice. It is quite common for a UI layer to query a model (DB) for some key, not knowing whether the key exists until a failed result comes back. The style question then is whether that failed result should manifest as an exception or not. Going down to the DB twice, once to establish the existence of the key and then again to get the associated value, expands the API in a way that's normally fine, but not always. There may also be synchronization issues. Here the key is an integer. – Steve Jessop Apr 13 '11 at 09:26
  • Now, the UI layer might well query the key immediately, in which case it has indeed sanitized the input "on the spot". But it has done it by means of a function of the model layer which accepts arbitrary input and checks it. To say that this model layer function must *only* sanitize (`is_valid_index`), and must not also be able to return the data (`at`, `map::find`, etc) is a mistake IMO. – Steve Jessop Apr 13 '11 at 09:34
  • @Konrad - How can the UI layer check the valid indexes in my manager class' private deque members? When the input eventually reaches them, through the intermediate layers, their sizes can have changed. – Bo Persson Apr 13 '11 at 09:59
  • @Bo: presumably in Konrad's design, if a lock needs to be taken then the UI takes it explicitly, or otherwise initiates a transaction that protects it from external changes. That's not necessarily a bad idea, since hidden locks have their own problems. For instance, using a checked accessor with its own lock, the UI/controller layers can't read-modify-write the value. Synchronization on its own isn't enough to demand a checked accessor, you usually need higher-level locking anyway, and hence could manage without the checked accessor. – Steve Jessop Apr 13 '11 at 10:20
  • @ildjam Which is exactly what I've been saying. – James Kanze Apr 13 '11 at 10:54
  • @Steve The analogy to `map::find` has convinced me. I was actually alluding to something equivalent to .NET’s `TryGetValue` but I can’t think of any reason why using an exception to signal failure is less appropriate here. – Konrad Rudolph Apr 13 '11 at 11:25
  • The big problem with the logic in this answer is this: "Accessing only within the valid bounds of a standard library container is a precondition of using that container" - that's just not true: `at()` documents defined behaviours for any index position you throw at it - there is no precondition on this. (If there was, `at()` could assert instead of throw.) You're generalising your overall impression of and preference for container interaction into a non-existant precondition for `at()`, rather than acknowledging that the exception (;-P) shows your conception and rule of thumb to be wrong. – Tony Delroy Nov 21 '12 at 03:40
  • @Tony : My point was that if you take everything _except_ `at` into account then the standard library is fairly consistent; `at` is the odd one out, and since when is that a good thing? – ildjarn Nov 21 '12 at 04:34
  • @ildjarn: if you code in a style that avoids the chance of getting exceptions, it's easy to not notice how many there are: lots of scenarios generate std::out_of_range and std::length_error from string operations (e.g. assign, insert, erase, replace, substr, append, push_back, reserve), vectors (reserve, at), bitset (set, reset, flip, test, to_ulong - overflow, constructor from strings of 0s and 1s - also std::invalid_argument)... not trying to be comprehensive here. – Tony Delroy Nov 21 '12 at 11:59
6

One use case I've consistently found at() useful in is facilitating parsing of complex user input. For example, in analysing C++ code, I find myself moving along an array of lexical tokens as I check for grammatical constructs. The logic is often like "if this token is an Identifier and the next one is an Equals then it should be an assignment so scan ahead for a Semicolon token to establish the token range for the expression". Using at() in such code means you can easily express expectations at some offset from the current point, ala:

if (tokens.at(i) == Switch)
{
    if (tokens.at(++i) != Left_Parentheses)
        // throw or return to say input program's broken...
    if (tokens.at(++i) == ...)
        ...
}

You get an exception whenever you try to parse an invalid program. Incrementing the position happens in so many places throughout the code that reverifying the size continually would be a nightmare (verbose and extremely error prone), as in this kind of situation you only realise how much bigger the program needs to be to be valid as the grammatical rules are applied. Using at() here is concise, robust, intuitive, and reasonably performant compared to functional equivalent alternatives.

FWIW - a quick search of our production code (200k lines, most written before I joined the team) found a dozen uses of at().

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
5

My case would rather be: why not use it ?

Unless you are in a performance critical part of your application, you should always favor std::out_of_range against Undefined Behavior, at least that's my credo.

In practice, I generally transform all the code I am working on to use checked accesses. The performance penalty is invisible for most of the code, and at least I've got a nice report with information on the current context of execution (generated in the catch(std::exception const&) at the root level) rather than a memory corruption that makes my code fail some times later (or worse, looks like it worked).

I agree that input should be validated first and foremost, I agree that you should check your access beforehand... but just in case you've forgotten or had a bug, better have a at().

Using [] instead of at() is like carrying a loaded gun without/with (resp.) the security on in your pocket. You can forget to put it on, but willingly removing it ? That's insanity.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 1
    @Matthieu: excellent, you're the hypothetical C++ programmer I described in one of my comments :-) That said, given how C++ is the rest of the time I think a better analogy would be carrying 12 loaded guns in your pocket, and `at()` puts a safety on one of them. The others don't have safeties. I suspect that's why most C++ programmers don't worry too much about the 1, they figure if they make any sudden movements it honestly doesn't matter whether they get shot in the foot 11 times or 12 - they're going to avoid sudden movements. – Steve Jessop Apr 13 '11 at 10:23
  • 1
    If you're using any good implementation of the library, the _undefined behavior_ is defined. To abort the program, which is what you want. If a precondition fails, you (usually) want to abort, without executing destructors. – James Kanze Apr 13 '11 at 10:52
  • @James Kanze: yes and no. In case of undefined behavior, I want an abort because the state is unknown. If a precondition fails, it depends on the execution environment: in test, abort and give me a nice core dump; in production, warn the user (gently) that something went awry and log as much as possible. Not responding to the user is among the most frustrating experiences you can provide. – Matthieu M. Apr 13 '11 at 11:26
  • 1
    @Matthieu : Which platform are you on, that an exception (such as std::out_of_range) gives "a nice report with traceback"? If the exception is caught, and I think it is extremely likely to be caught, because it is a std::exception derived object, you normally got zero traceback information, and if the exception ain't caught, you're program is terminated, just as it very likely would be in case of invalid index access. – Martin Ba Apr 13 '11 at 12:44
  • @Martin: `std::out_of_range` itself won't be caught, but it's executed from within a `Command` which catch all `std::exception` that escape and rethrow its own exception with details on the current session, as well as print a dump of the current execution context. Our own exceptions would provide a traceback, but I mixed the two. – Matthieu M. Apr 13 '11 at 13:00
  • @James: "any good implementation, the undefined behaviour is defined"... maybe with certain debug-builds compiler options, but certainly not true in general: `vector::operator[]` is expected to be, is, and can only be as fast as C-style array indexing because it doesn't waste time doing checks and conditional defined behaviours. You can prove it to yourself with a 5 line program - I just did for GCC 4.5.2. – Tony Delroy Apr 15 '11 at 02:14
  • @Tony You choose the compiler options you want or need. Unless the profiler says otherwise, you leave on full checking. And if the profiler says you can't afford the test, you can't afford it to generate an exception either, so you can't use `at()`. – James Kanze Apr 15 '11 at 09:04
  • 1
    @James: `at` is used on a per-case basis. You can decide to forgo it in a tight loop, for example. The compiler options affect the whole translation unit. And I would definitely be interested in knowing which compiler option you're talking about, I didn't know such existed (only knew about checked STL, but it's so slow it cannot be activated for production... and there is the binary compatibility issue) – Matthieu M. Apr 15 '11 at 09:21
  • @Matthieu M. I agree that a better design would have had [] with a required abort in case of an error, and an `unsafe_at` function as the only way of avoiding any error checking. And you're (regretfully) right about the other issue: the checking is everything or nothing, both with regards to what is being checked, and the fact that you can't switch it on and off selectively within an executable, much less a translation unit. Still, most of the applications I've worked on have left it on in production. – James Kanze Apr 15 '11 at 11:43
4

After a quick search, I found that, among others, Inkscape (the svg editor), Google v8, Android, Chromium, and Ogre used this function. This (rudimentary) list was taken from a simple google search, using the regular expression at\([0-9]+\).

Using \.at\([0-9a-z_]+\) instead of the previous expression gives more generic results, and adds OpenJdk and a wealth of sourceforge projects.

Martin Ba
  • 37,187
  • 33
  • 183
  • 337
Clément
  • 12,299
  • 15
  • 75
  • 115
0

Stroustrup recommends use of at at all places except when you are sure that the index will be inside the valid range.

He recommends that for code like the below one can use the [] operator.

for (int i = 0; i < v.size(); ++i)
{
    // use v[i] - we are sure it will be a valid index
}

In other cases, use at

user93353
  • 13,733
  • 8
  • 60
  • 122
0

v.at(-1) won't fail like v[-1] (you'll get an exception)

Nikolay Yordanov
  • 1,404
  • 16
  • 25
0

I agree with many people here that at is mostly useless; however it might look better when working with pointers to (or lists of) containers:

std::vector<std::vector<int> >::iterator i;
for (i = v2.begin(); i != v2.end(); ++i)
{
    int x1 = (*i)[3]; // UGLY
    int x2 = i->at(3); // Looks OK
}

I think this code looks better when using at.

anatolyg
  • 26,506
  • 9
  • 60
  • 134