cppreference cplusplus c++ c++11 iterator const-correctness const-iterator

c++ - cplusplus - vector cppreference



¿Cuál es la razón detrás de cbegin/cend? (6)

Acabo de tropezar con esta pregunta ... Sé que ya está respondida y es solo un nodo lateral ...

auto const it = container.begin() es un tipo diferente y luego auto it = container.cbegin()

la diferencia para int[5] (usando el puntero, que sé que no tiene el método begin pero muestra bien la diferencia ... pero funcionaría en c ++ 14 para std::cbegin() y std::cend() , que es esencialmente lo que uno debería usar cuando está aquí) ...

int numbers = array[7]; const auto it = begin(numbers); // type is int* const -> pointer is const auto it = cbegin(numbers); // type is int const* -> value is const

Me pregunto por qué cbegin y cend se introdujeron en C ++ 11?

¿Cuáles son los casos cuando llamar a estos métodos hace una diferencia con las sobrecargas de begin y end ?


De http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :

para que un programador pueda obtener directamente un const_iterator incluso desde un contenedor no const

Ellos dieron este ejemplo

vector<MyType> v; // fill v ... typedef vector<MyType>::iterator iter; for( iter it = v.begin(); it != v.end(); ++it ) { // use *it ... }

Sin embargo, cuando un cruce de contenedores está destinado a inspección solamente, es una práctica generalmente preferida usar un const_iterator para permitir que el compilador diagnostique las violaciones de const-correctness

Tenga en cuenta que el documento de trabajo también menciona las plantillas de adaptador, que ahora se han finalizado como std::begin() y std::end() y que también funcionan con matrices nativas. El std::cbegin() y std::cend() correspondientes están curiosamente ausentes a partir de este momento, pero también pueden ser agregados.


Es bastante simple. Digamos que tengo un vector:

std::vector<int> vec;

Lo llené con algunos datos. Entonces quiero obtener algunos iteradores. Quizás pasarlos. Tal vez para std::for_each :

std::for_each(vec.begin(), vec.end(), SomeFunctor());

En C ++ 03, SomeFunctor fue libre de poder modificar el parámetro que obtiene. Claro, SomeFunctor podría tomar su parámetro por valor o por const& , pero no hay manera de asegurarse de que lo haga. No sin hacer algo tonto como este:

const std::vector<int> &vec_ref = vec; std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());

Ahora, presentamos cbegin/cend :

std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());

Ahora, tenemos garantías sintácticas de que SomeFunctor no puede modificar los elementos del vector (sin un molde constante, por supuesto). Obtenemos explícitamente const_iterator s, y por lo tanto SomeFunctor :: operator () se llamará con const int & . Si toma sus parámetros como int & , C ++ emitirá un error de compilación.

C ++ 17 tiene una solución más elegante para este problema: std::as_const . Bueno, al menos es elegante cuando se usa el rango for :

for(auto &item : std::as_const(vec))

Esto simplemente devuelve un const& al objeto que se proporciona.


Más allá de lo que dijo Nicol Bolas en su respuesta , considere la nueva palabra clave auto :

auto iterator = container.begin();

Con auto , no hay forma de asegurarse de que begin() devuelve un operador constante para una referencia de contenedor no constante. Entonces ahora lo haces:

auto const_iterator = container.cbegin();


Toma esto como un uso práctico

void SomeClass::f(const vector<int>& a) { auto it = someNonConstMemberVector.begin(); ... it = a.begin(); ... }

La asignación falla porque es un iterador no consistente. Si utilizó cbegin inicialmente, el iterador tendría el tipo correcto.


const_iterator y const_iterator tienen una relación de herencia y se produce una conversión implícita cuando se compara con o se asigna al otro tipo.

class T {} MyT1, MyT2, MyT3; std::vector<T> MyVector = {MyT1, MyT2, MyT3}; for (std::vector<T>::const_iterator it=MyVector.begin(); it!=MyVector.end(); ++it) { // ... }

Usar cbegin() y cend() aumentará el rendimiento en este caso.

for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it) { // ... }