significado objetos mutables inmutables inmutable inmutabilidad ejemplos c++ string c++11 containers c-strings

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 cualquier n en [ 0 , s.size() ), o, de manera equivalente, se puede pasar un puntero a s[0] a funciones que esperan un puntero al primer elemento de una matriz CharT[] .

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 .