example - vector insert c++
¿C++ 11 permite vector<const T>? (4)
Aunque ya tenemos muy buenas respuestas sobre esto, decidí contribuir con una respuesta más práctica para mostrar lo que se puede y no se puede hacer.
Entonces esto no funciona:
vector<const T> vec;
Simplemente lea las otras respuestas para entender por qué. Y, como habrás adivinado, esto tampoco funcionará:
vector<const shared_ptr<T>> vec;
T
ya no es const
, pero el vector
contiene shared_ptr
s, no T
s.
Por otro lado, esto funciona:
vector<const T *> vec;
vector<T const *> vec; // the same as above
Pero en este caso, const es el objeto al que se apunta, no el puntero en sí (que es lo que almacena el vector). Esto sería equivalente a:
vector<shared_ptr<const T>> vec;
Lo cual está bien.
Pero si ponemos const
al final de la expresión, ahora convierte el puntero en un const
, por lo que no se compilará lo siguiente:
vector<T * const> vec;
Un poco confuso, estoy de acuerdo, pero te acostumbras.
Los requisitos del contenedor han cambiado de C ++ 03 a C ++ 11. Si bien C ++ 03 tenía requisitos generales (por ejemplo, copia de la capacidad de construcción y de asignabilidad para el vector), C ++ 11 define requisitos precisos en cada operación del contenedor (sección 23.2).
Como resultado, puede, por ejemplo, almacenar un tipo que sea copiable pero no asignable, como una estructura con un elemento constante, en un vector siempre que solo realice ciertas operaciones que no requieren asignación (construcción y push_back
son tales operaciones; insert
no es).
Lo que me pregunto es: ¿significa esto que el estándar ahora permite vector<const T>
? No veo ninguna razón por la que no debería - const T
, al igual que una estructura con un miembro de const, es un tipo que es copiable pero no asignable, pero es posible que haya pasado algo por alto.
(Parte de lo que me hace pensar que me he perdido algo, es que el tronco gcc se cuelga y quema si intentas crear una instancia del vector<const T>
, pero está bien con el vector<T>
donde T tiene un miembro const).
Complementando las otras respuestas, otro enfoque es usar:
vector<unique_ptr<const T>> vec;
Si es el caso donde desea hacer cumplir, solo el vec
tiene la propiedad de sus elementos. O si desea una dinámica de mover elementos a vec
y en algún momento moverlos.
Como se señaló, la semántica const
puntero puede ser confusa, pero shared_ptr
y unique_ptr
no lo son. const unique_ptr<T>
es un const pointer y unique_ptr<const T>
es un const pointee como es de esperar.
No, creo que los requisitos del asignador dicen que T puede ser un "tipo de objeto no const, no de referencia".
No sería capaz de hacer mucho con un vector de objetos constantes. Y un const vector<T>
sería casi igual de todos modos.
Muchos años después, esta respuesta rápida y sucia todavía parece atraer comentarios y votos. No siempre está arriba. :-)
Entonces, para agregar algunas referencias apropiadas:
Para el estándar C ++ 03, que tengo en papel, la Tabla 31 en la sección [lib.allocator.requirements] dice:
T, U any type
No es que ningún tipo realmente funcionó.
Por lo tanto, el siguiente estándar, C ++ 11, dice en un borrador detallado en [allocator.requirements] y ahora en la Tabla 27:
T, U, C any non-const, non-reference object type
que es extremadamente cercano a lo que originalmente escribí arriba de memoria. De eso también se trataba la pregunta.
Sin embargo, en C ++ 14 ( borrador N4296 ), la Tabla 27 ahora dice:
T, U, C any non-const object type
Posiblemente porque una referencia tal vez no sea un tipo de objeto después de todo?
Y ahora en C ++ 17 ( borrador N4659 ) es la Tabla 30 que dice:
T, U, C any cv-unqualified object type (6.9)
Entonces, no solo se excluye el const
, sino que también es volatile
. Probablemente sean noticias viejas de todos modos, y solo una aclaración.
Consulte también la información de primera mano de Howard Hinnant , que se encuentra justo debajo.
Actualizar
Debajo de la respuesta aceptada (y correcta) que comenté en 2011:
En pocas palabras: no diseñamos contenedores para mantener
const T
Aunque lo pensé un poco. Y estuvimos muy cerca de hacerlo por accidente. Hasta donde yo sé, el punto de fricción actual es el par de funciones de miembro deaddress
sobrecargadas en el asignador predeterminado: cuandoT
esconst
, estas dos sobrecargas tienen la misma firma. Una manera fácil de corregir esto sería especializarstd::allocator<const T>
y eliminar una de las sobrecargas.
Con el próximo borrador de C ++ 17, me parece que ahora hemos legalizado el vector<const T>
, y también creo que lo hemos hecho accidentalmente . :-)
P0174R0 elimina las sobrecargas de address
de std::allocator<T>
. P0174R0 no menciona el soporte de std::allocator<const T>
como parte de su fundamento.
Corrección
En los comentarios a continuación, TC señala correctamente que las sobrecargas de address
están en desuso , no eliminadas. Mi error. Los miembros obsoletos no aparecen en 20.10.9 donde se define std::allocator
, sino que se relegan a la sección D.9. Descuidé escanear el Capítulo D para esta posibilidad cuando publiqué esto.
Gracias TC por la corrección. Consideré eliminar esta respuesta engañosa, pero tal vez sea mejor dejarlo con esta corrección para que tal vez evite que alguien más malinterprete las especificaciones de la misma manera que yo.