Me pregunto por qué cbeginy cendse introdujeron en C ++ 11?
¿Cuáles son los casos en los que llamar a estos métodos marca la diferencia de las sobrecargas constantes de beginy end?
Me pregunto por qué cbeginy cendse introdujeron en C ++ 11?
¿Cuáles son los casos en los que llamar a estos métodos marca la diferencia de las sobrecargas constantes de beginy end?
Es bastante simple. Digamos que tengo un vector:
std::vector<int> vec;
Lo lleno con algunos datos. Entonces quiero obtener algunos iteradores. Quizás pasarlos por ahí. Quizás para std::for_each:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
En C ++ 03, SomeFunctorera libre de poder modificar el parámetro que obtiene. Claro, SomeFunctorpodría tomar su parámetro por valor o por const&, pero no hay forma 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 que SomeFunctorno pueden modificar los elementos del vector (sin un const-cast, por supuesto). Obtenemos explícitamente const_iterators, y por SomeFunctor::operator()lo tanto 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 a este problema: std::as_const. Bueno, al menos es elegante cuando se usa basado en rango for:
for(auto &item : std::as_const(vec))
Esto simplemente devuelve const&a al objeto que se proporciona.
std::cbegin/cendfunciones libres comostd::begin/std::endexisten. Fue un descuido por parte del comité. Si esas funciones existieran, esa sería generalmente la forma de usarlas.std::cbegin/cendse agregará en C ++ 14. Ver en.cppreference.com/w/cpp/iterator/beginfor(auto &item : std::as_const(vec))equivalente afor(const auto &item : vec)?consten la referencia. Nicol ve el contenedor como constante, por lo queautodeduce unaconstreferencia. La OMIauto const& itemes más fácil y más clara. No está claro por quéstd::as_const()es bueno aquí; Puedo ver que sería útil cuando se pasa algo que noconstes código genérico donde no podemos controlar el tipo que se usa, pero con rangofor, podemos hacerlo, por lo que me parece un ruido agregado allí.Más allá de lo que dijo Nicol Bolas en su respuesta , considere la nueva
autopalabra clave:Con
auto, no hay forma de asegurarse de quebegin()devuelva un operador constante para una referencia de contenedor no constante. Entonces ahora lo haces:fuente
const_iteratores solo otro identificador. Ninguna de las versiones utiliza una búsqueda de los miembros habituales typedefsdecltype(container)::iteratorodecltype(container)::const_iterator.const_iteratorconauto: Escriba una plantilla de función auxiliar llamadamake_constpara calificar el argumento del objeto.Tome esto como un caso práctico
La asignación falla porque
ites un iterador no constante. Si usó cbegin inicialmente, el iterador habría tenido el tipo correcto.fuente
De http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf :
Dieron este ejemplo
Tenga en cuenta que el documento de trabajo también menciona plantillas de adaptadores, que ahora se han finalizado como
std::begin()ystd::end()y que también funcionan con matrices nativas. Los correspondientesstd::cbegin()ystd::cend()curiosamente faltan a partir de este momento, pero también podrían agregarse.fuente
Me topé con esta pregunta ... Sé que ya está respondida y es solo un nodo lateral ...
auto const it = container.begin()es un tipo diferente entoncesauto it = container.cbegin()la diferencia para
int[5](usando el puntero, que sé que no tiene el método de inicio, pero muestra muy bien la diferencia ... pero funcionaría en c ++ 14 parastd::cbegin()ystd::cend(), que es esencialmente lo que uno debería usar cuando está aquí) ...fuente
iteratoryconst_iteratortienen una relación de herencia y se produce una conversión implícita cuando se compara o se asigna al otro tipo.Usando
cbegin()ycend()aumentará el rendimiento en este caso.fuente
constel principal beneficio es el rendimiento (que no lo es: es un código semánticamente correcto y seguro). Pero, si bien tiene un punto, (A)autohace que no sea un problema; (B) al hablar sobre el rendimiento, se perdió una cosa principal que debería haber hecho aquí: almacenar en caché elenditerador declarando una copia de él en la condición init delforbucle, y compararlo, en lugar de obtener una nueva copia valor para cada iteración. Eso mejorará tu punto. : Pconstdefinitivamente puede ayudar a lograr un mejor rendimiento, no debido a cierta magia en laconstpalabra clave en sí, sino porque el compilador puede habilitar algunas optimizaciones si sabe que los datos no se modificarán, lo que de otra manera no sería posible. Mira este fragmento de la charla de Jason Turner para ver un ejemplo en vivo de esto.constpuede (casi indirectamente) conducir a beneficios de rendimiento; por si alguien que lee esto puede pensar "No me molestaré en agregarconstsi el código generado no se ve afectado de ninguna manera", lo cual no es cierto.es simple, cbegin devuelve un iterador constante donde begin solo devuelve un iterador
para una mejor comprensión, tomemos dos escenarios aquí
escenario 1 :
esto se ejecutará porque aquí el iterador i no es constante y puede incrementarse en 5
ahora usemos cbegin y cend denotándolos como escenario de iteradores constantes - 2:
esto no va a funcionar, porque no puede actualizar el valor usando cbegin y cend, que devuelve el iterador constante
fuente