简体   繁体   中英

Why does .at() member function of a vector return a reference instead of an iterator?

Up until a few days ago I thought all 'position' related member functions of a vector returned an iterator . I found out recently that while insert() and erase() functions do indeed return iterators , begin() and end() do so by definition, but functions like at() , front() , back() do not do so, they return a simple reference.

While references make life easier as I would not have to dereference the iterator fist, to me it still seems inconsistent that some member functions are returning a reference instead of an iterator. If anything, C++ tries to minimize inconsistencies like this by providing the bare minimum while still maintaining ease in programming.

at method is from the group of common container methods called 'Element access', those return reference, pointers. There is another group of common container methods called 'Iterators', those return iterators. It is clear, simple and well-known design decision for the standard library.

Element access

  • at : access specified element with bounds checking
  • operator[] : access specified element
  • front : access the first element
  • back : access the last element
  • data direct access to the underlying array

Iterators

  • begin / cbegin returns an iterator to the beginning
  • end / cend returns an iterator to the end
  • rbegin / crbegin returns a reverse iterator to the beginning
  • rend / crend returns a reverse iterator to the end

In the iterator concept, elements within iterator range are accessed through std::advance method of STD. This would work for InputIterator s, for BST, list, vectors, etc., of course with different complexity.

begin() , end() , insert() , erase() , etc. are methods that work on the vectors' sequence of elements itself, while operator [] , at() , front() , and back() are methods that access concrete elements of this sequence. I don't really see an inconsistency here. They exist for all sequence containers and they always do conceptually the same thing. Sure, you could implement something like front() and back() yourself, nothing keeps you from doing so. They are by definition equivalent to dereferencing begin() and prev(end()) respectively. They exist for convenience. Depending on how far you want to go, std::vector itself exists just for convenience…

The abstraction that the Standard Template Library presents is sequences , iterators , and algorithms . Container are one way of creating and managing sequences, but they are not the only way. For example, an input stream can be used as a sequence, by creating a std::istream_iterator . But things like int i; double d; std::cin >> i >> d; int i; double d; std::cin >> i >> d; would be rather awkward to write if std::cin only defined an iterator-based interface. Same thing for containers: they're useful in contexts other than iteration, and they define interfaces appropriate to their general uses; one of those uses is as a sequence for STL algorithms, but there are other uses, too.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM