c++ - inmutabilidad - objetos mutables e inmutables java
¿Por qué string:: data() no proporciona un carácter mutable*? (2)
Creo que esta restricción proviene de los días (anteriores a 2011) donde std::basic_string
no tuvo que almacenar su búfer interno como una matriz de bytes contigua.
Mientras que todos los demás ( std::vector
y similares) tenían que almacenar sus elementos como una secuencia contigua según la norma 2003; así que los data
podrían devolver fácilmente T*
mutable, porque no hubo problemas con las iteraciones, etc.
Si std::basic_string
devolviera un char*
mutable char*
, eso implicaría que puede tratar a ese char*
como una cadena C válida y realizar operaciones de cadena C como strcpy
, que se convertiría fácilmente en un comportamiento indefinido si la cadena no estuviera asignada contiguamente
El estándar C ++ 11 agregó la regla de que basic_string
debe implementarse como una matriz de bytes contiguos. No hace falta decir que puede solucionar esto utilizando el viejo truco de &str[0]
.
En c ++ 11 , la array
, la string
y el vector
obtuvieron el método de data
que:
Devuelve el puntero a la matriz subyacente que sirve como almacenamiento de elementos. El puntero es tal que rango [
data()
;data() + size()
) siempre es un rango válido, incluso si el contenedor está vacío. [ Source ]
Este método se proporciona en una versión mutable y const
para todos los contenedores aplicables, por ejemplo:
T* vector<T>::data();
const T* vector<T>::data() const;
Todos los contenedores aplicables, es decir, excepto la string
que solo proporciona la versión const
:
const char* string::data() const;
¿Lo que pasó aquí? ¿Por qué se cortó la string
cuando char* string::data()
sería tan útil?
La respuesta corta es que c ++ 17 proporciona el método char* string::data()
. Lo que es vital para la función de data
similar a c ++ 17 , por lo tanto, para obtener acceso mutable al C-String subyacente, ahora puedo hacer esto:
auto foo = "lorem ipsum"s;
for(auto i = data(foo); *i != ''/0''; ++i) ++(*i);
Para propósitos históricos, vale la pena string
el desarrollo de la string
en la que se basa c ++ 17 : En c ++ 11, el acceso al búfer subyacente de la string
es posible gracias a un nuevo requisito de que sus elementos se almacenen de forma contigua, de manera que para cualquier string s
&*(s.begin() + n) == &*s.begin() + n
para cualquiern
en [0
,s.size()
), o, de manera equivalente, se puede pasar un puntero as[0]
a funciones que esperan un puntero al primer elemento de una matrizCharT[]
.
El acceso mutable a esta nueva C-String subyacente se pudo obtener mediante varios métodos, por ejemplo: &s.front()
, &s[0]
, o &*s.first()
Pero volviendo a la pregunta original, que evitaría la carga de usando una de estas opciones: ¿Por qué no se ha proporcionado acceso al búfer subyacente de la string
en forma de char* string::data()
?
Para responder que es importante tener en cuenta que T* array<T>::data()
y T* vector<T>::data()
eran una adición requerida por c ++ 11 . C ++ 11 no incurrió en requisitos adicionales contra otros contenedores contiguos como el deque
. Y ciertamente no hubo un requisito adicional para la string
, de hecho, el requisito de que la string
fuera contigua era nuevo para c ++ 11 . Antes de este const char* string::data()
había existido. Aunque no se garantizaba explícitamente que apuntara a ningún búfer subyacente, era la única forma de obtener un const char*
de una string
:
No se requiere que la matriz devuelta sea terminada en nulo.
Esto significa que la string
no se "abrevió" en la transición de c ++ 11 a los accesores de data
, simplemente no se incluyó, por lo que solo persistió el accesorio de data
const
que la string
poseía anteriormente. Hay ejemplos que ocurren naturalmente en la implementación de C ++ 11 que requieren escribir directamente en el búfer subyacente de una string
.