sirve que para mid c++ string substring lvalue

mid - substr c++ para que sirve



¿Por qué no es un error del compilador asignar al resultado de una llamada substr? (3)

El resultado de substr() es un objeto temporal std::string : es una copia autocontenida de la subcadena, no una vista de la cadena original.

Al ser un objeto std::string , tiene una función de operador de asignación, y su código invoca esa función para modificar el objeto temporal.

Esto es un poco sorprendente: modificar un objeto temporal y descartar el resultado generalmente indica un error lógico, por lo que, en general, hay dos formas en que las personas intentan mejorar la situación:

  1. Devuelve un objeto const .
  2. Utilice lvalue ref-qualifier en el operador de asignación.

La opción 1 causaría un error de compilación para su código, pero también restringe algunos casos de uso válidos (por ejemplo, move el valor de retorno, no puede salir de una cadena const ).

La opción 2 impide que se utilice el operador de asignación a menos que el lado izquierdo sea un valor l. Esta es una buena idea, aunque no todos están de acuerdo; ver este hilo de discusión .

En todo caso; cuando se agregaron ref-calificadores en C ++ 11 , se propuso regresar y cambiar la especificación de todos los contenedores de C ++ 03, pero esta propuesta no fue aceptada (probablemente, en caso de que rompiera el código existente).

std::string se diseñó en la década de 1990 e hizo algunas elecciones de diseño que hoy parecen ser deficientes en retrospectiva, pero estamos atascados en ello. Tendrá que entender el problema de std::string sí mismo, y tal vez evitarlo en sus propias clases mediante el uso de ref-qualifiers, vistas o lo que sea.

Acabo de descubrir el error más desconcertante y no entiendo por qué el compilador no me lo marcó. Si escribo lo siguiente:

string s = "abcdefghijkl"; cout << s << endl; s.substr(2,3) = "foo"; s.substr(8,1) = ''.''; s.substr(9,1) = 4; cout << s << endl;

El compilador no tiene ningún problema con esto, y las declaraciones de asignación parecen no tener ningún efecto, según lo que se imprimió. A diferencia de,

s.front() = ''x'';

tiene el efecto que esperaría (ya que el front devuelve una referencia a un carácter) de cambiar la cadena subyacente, y

s.length() = 4;

también tiene el efecto esperado de generar un error de compilación quejándose de que no se puede asignar a algo que no sea un valor lime, porque la length devuelve un entero. (Bueno, un size_t todos modos.)

Entonces ... ¿por qué demonios el compilador no se queja de asignar el resultado de una llamada a substr ? Devuelve un valor de cadena, no una referencia, por lo que no debería ser asignable, ¿verdad? Pero he intentado esto en g++ (6.2.1) y clang++ (3.9.0), por lo que no parece ser un error, y tampoco parece ser sensible a la versión de C ++ (probado 03, 11 , 14).


La razón por la que su código compila es porque es legal C ++. Aquí hay un enlace que explica lo que está pasando.

https://accu.org/index.php/journals/227

Es bastante largo, así que citaré la parte más relevante:

Los valores no de clase no son modificables, ni pueden tener tipos calificados para CV (se ignoran las calificaciones CV). Por el contrario, los valores de la clase son modificables y se pueden usar para modificar un objeto a través de sus funciones miembro. También pueden tener tipos cv calificados.

Por lo tanto, la razón por la que no puede asignar el rvalue devuelto por std::string::length es que no es una instancia de una clase, y la razón por la que puede asignar el rvalue devuelto por std::string::substr Es porque es una instancia de una clase.

No entiendo bien por qué el lenguaje se define de esta manera, pero así es como es.


Mira el código:

s.substr(2,3) = "foo";

La llamada de función a substr devuelve una cadena, que es un objeto y un valor temporal. Después de eso, modifica este objeto (en realidad llamando al operador de asignación sobrecargado desde la clase std::string ). Este objeto temporal no se guarda de ninguna manera. El compilador simplemente destruye este temporal modificado.

Este código no tiene sentido. Puedes preguntar, ¿por qué el compilador no da una advertencia? La respuesta es que el compilador podría ser mejor. Los compiladores están escritos por personas, no por dioses. Desafortunadamente, C ++ permite toneladas de varias formas de escribir código sin sentido o código que desencadena un comportamiento indefinido. Este es uno de los aspectos de este lenguaje. Requiere un mejor conocimiento y una mayor atención por parte del programador en comparación con muchos otros idiomas.

Acabo de consultar con MSVC 2015, el código:

std::string s1 = "abcdef"; s1.substr(1, 2) = "5678";

compila bien