C++ Iterando Sobre std :: vector


Ejemplo

Puedes iterar sobre un std::vector de varias maneras. Para cada una de las siguientes secciones, v se define como sigue:

std::vector<int> v;

Iterando en la dirección hacia adelante

C ++ 11
// Range based for
for(const auto& value: v) {
    std::cout << value << "\n";
}

// Using a for loop with iterator
for(auto it = std::begin(v); it != std::end(v); ++it) {
    std::cout << *it << "\n";
}

// Using for_each algorithm, using a function or functor:
void fun(int const& value) {
    std::cout << value << "\n";
}

std::for_each(std::begin(v), std::end(v), fun);

// Using for_each algorithm. Using a lambda:
std::for_each(std::begin(v), std::end(v), [](int const& value) {
    std::cout << value << "\n";
});
C ++ 11
// Using a for loop with iterator
for(std::vector<int>::iterator it = std::begin(v); it != std::end(v); ++it) {
    std::cout << *it << "\n";
}
// Using a for loop with index
for(std::size_t i = 0; i < v.size(); ++i) {
    std::cout << v[i] << "\n";
}

Iterando en la dirección inversa

C ++ 14
// There is no standard way to use range based for for this.
// See below for alternatives.

// Using for_each algorithm
// Note: Using a lambda for clarity. But a function or functor will work
std::for_each(std::rbegin(v), std::rend(v), [](auto const& value) {
    std::cout << value << "\n";
});

// Using a for loop with iterator
for(auto rit = std::rbegin(v); rit != std::rend(v); ++rit) {
    std::cout << *rit << "\n";
}
// Using a for loop with index
for(std::size_t i = 0; i < v.size(); ++i) {
    std::cout << v[v.size() - 1 - i] << "\n";
}

Aunque no hay una forma integrada de usar el rango para revertir iteración; Es relativamente sencillo arreglar esto. El rango basado en los usos begin() y end() para obtener iteradores y, por lo tanto, simular esto con un objeto de envoltura puede lograr los resultados que requerimos.

C ++ 14
template<class C>
struct ReverseRange {
  C c; // could be a reference or a copy, if the original was a temporary
  ReverseRange(C&& cin): c(std::forward<C>(cin)) {}
  ReverseRange(ReverseRange&&)=default;
  ReverseRange& operator=(ReverseRange&&)=delete;
  auto begin() const {return std::rbegin(c);}
  auto end()   const {return std::rend(c);}
};
// C is meant to be deduced, and perfect forwarded into
template<class C>
ReverseRange<C> make_ReverseRange(C&& c) {return {std::forward<C>(c)};}

int main() {
    std::vector<int> v { 1,2,3,4};
    for(auto const& value: make_ReverseRange(v)) {
        std::cout << value << "\n";
    }
}

Hacer cumplir elementos const

Desde C ++ 11, los cbegin() y cend() permiten obtener un iterador constante para un vector, incluso si el vector no es constante. Un iterador constante le permite leer pero no modificar los contenidos del vector, lo que es útil para imponer la corrección constante:

C ++ 11
// forward iteration
for (auto pos = v.cbegin(); pos != v.cend(); ++pos) {
   // type of pos is vector<T>::const_iterator
   // *pos = 5; // Compile error - can't write via const iterator
}

// reverse iteration
for (auto pos = v.crbegin(); pos != v.crend(); ++pos) {
   // type of pos is vector<T>::const_iterator
   // *pos = 5; // Compile error - can't write via const iterator
}

// expects Functor::operand()(T&) 
for_each(v.begin(), v.end(), Functor());

// expects Functor::operand()(const T&)
for_each(v.cbegin(), v.cend(), Functor())
C ++ 17

as_const extiende esto a la iteración de rango:

for (auto const& e : std::as_const(v)) {
  std::cout << e << '\n';
}

Esto es fácil de implementar en versiones anteriores de C ++:

C ++ 14
template <class T>
constexpr std::add_const_t<T>& as_const(T& t) noexcept {
  return t;
}

Una nota sobre la eficiencia

Dado que la clase std::vector es básicamente una clase que administra una matriz contigua asignada dinámicamente, el mismo principio explicado aquí se aplica a los vectores C ++. El acceso al contenido del vector por índice es mucho más eficiente cuando se sigue el principio de orden de fila mayor. Por supuesto, cada acceso al vector también pone su contenido de administración en el caché, pero como se ha debatido muchas veces (especialmente aquí y aquí ), la diferencia en el rendimiento para iterar sobre un std::vector comparación con una matriz en bruto es despreciable. Por lo tanto, el mismo principio de eficiencia para matrices en bruto en C también se aplica para std::vector de C ++.