En C++11 y más allá, ¿std::string::operator[] hace la comprobación de límites?


He visto muchas veces que std::string::operator[] no hace ninguna comprobación de límites. Even ¿Cuál es la diferencia entre el operador string::at y string:: []?, preguntado en 2013, las respuestas dicen que operator[] no hace ninguna verificación de límites.

Mi problema con esto es si miro el estándar (en este caso borrador N3797) en [cadena.acceso] tenemos

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
  1. Requiere: pos <= size().
  2. Devuelve: *(begin() + pos) if pos < size(). De lo contrario, devuelve una referencia a un objeto de tipo charT con valor charT(), donde modificar el objeto conduce a un comportamiento indefinido.
  3. Lanza: Nada.
  4. Complejidad: tiempo constante.

Esto me lleva a creer que operator[] tiene que hacer algún tipo de comprobación de límites para determinar si necesita devolver un elemento de la cadena o un valor predeterminado charT. ¿Es esta suposición correcta y operator[] ahora se requiere hacer la comprobación de límites?

Author: Community, 2016-07-21

5 answers

La redacción es un poco confusa, pero si la estudias en detalle descubrirás que en realidad es muy precisa.

Dice esto:

  • La condición previa es que el argumento [] es = n o n.
  • Suponiendo que se cumple esa condición previa:
    • Si es n entonces obtienes el carácter que pediste.
    • " Otherwise " (i. e. if it's n) then you get charT() (i. e. the null caracter).

Pero no se define ninguna regla para cuando se rompe la precondición, y la comprobación de = n se puede cumplir implícitamente (pero no se requiere explícitamente) almacenando realmente un charT() en la posición n.

Así que las implementaciones no necesitan realizar ninguna comprobación de límites {y las comunes no lo harán.

 44
Author: Lightness Races in Orbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-22 16:06:17

operator[] tiene que hacer algún tipo de verificación de límites para determinar...

No, no lo hace. Con la precondición

Requiere: pos

Puede simplemente ASUMIR que siempre puede devolver un elemento de la cadena. Si no se cumple esta condición: Comportamiento indefinido.

El operator[] probablemente solo incrementará el puntero desde el inicio de la cadena por pos. Si la cadena es más corta, entonces solo devuelve una referencia a los datos detrás de la cuerda, sea lo que sea. Como un clásico fuera de límites en matrices C simples.

Para completar el caso de donde pos == size() solo podría haber asignado un charT extra al final de sus datos de cadena internos. Así que simplemente incrementando el puntero sin ninguna comprobación, todavía entregaría el comportamiento indicado.

 14
Author: Superlokkus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-03 11:06:43

Primero, hay una cláusula requires. Si usted viola la cláusula requires, su programa se comporta de una manera indefinida. Eso es pos <= size().

Así que el lenguaje solo define lo que sucede en ese caso.

El siguiente párrafo establece que para pos < size(), devuelve una referencia a un elemento en la cadena. Y para pos == size(), devuelve una referencia a un valor predeterminado construido charT con el valor charT().

Si bien esto puede parecer verificación de límites, en la práctica lo que realmente sucede es que el std::basic_string asigna un búfer más grande que el pedido y rellena la última entrada con un charT(). Entonces [] simplemente hace puntero aritemético.

He tratado de encontrar una manera de evitar esa implementación. Si bien la norma no lo exige, no pude convencerme de que exista una alternativa. Había algo molesto con .data() que hacía difícil evitar el búfer único.

 4
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 14:20:14

Este operador de contenedores estándar emula el comportamiento del operador [] de matrices ordinarias. Así que no hace ningún control. Sin embargo, en el modo de depuración, la biblioteca correspondiente puede proporcionar esta comprobación.

Si desea verificar el índice, use la función miembro at() en su lugar.

 2
Author: Vlad from Moscow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 14:16:47

Http://en.cppreference.com/w/cpp/string/basic_string/operator_at

Devuelve una referencia al carácter en la ubicación especificada pos. No se realiza la comprobación de límites.

(Énfasis mío).

Si quieres comprobar los límites, usa std:: basic_string:: at

El estándar implica que la implementación necesita proporcionar verificación de límites porque básicamente describe lo que hace un acceso a una matriz sin marcar.

Si accede dentro de los límites, está definido. Si sale, desencadena un comportamiento indefinido.

 1
Author: PSkocik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-21 14:22:50