biblioteca array c++ string c++11 c++14 arrayaccess

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



std::array (5)

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

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

const_reference operator[](size_type pos) const; reference operator[](size_type pos);

  1. Requiere: pos <= size() .
  2. Devuelve: *(begin() + pos) si pos < size() . De lo contrario, devuelve una referencia a un objeto de tipo charT con el valor charT() , donde la modificación del objeto conduce a un comportamiento indefinido.
  3. Tiros: Nada.
  4. Complejidad: tiempo constante.

Esto me lleva a creer que el 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 carácter predeterminado. ¿Es correcto este supuesto y ahora se requiere que el operator[] realice la verificación de límites?


operator[] ha realizado algún tipo de comprobación de límites para determinar ...

No, no lo hace. Con la precondición

Requiere: pos <= tamaño ().

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

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

Para completar el caso de donde pos == size() podría haber asignado un carácter adicional al final de sus datos de cadena internos. Por lo tanto, solo incrementar el puntero sin ningún tipo de comprobación, aún ofrecería el comportamiento indicado.


Este operador de contenedores estándar emula el comportamiento del operador [] de matrices ordinarias. Así que no hace ningún cheque. 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() lugar.


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

Dice esto:

  • La condición previa es que el argumento de [] sea ​​= n o sea < n .
  • Suponiendo que se cumpla la condición previa:
    • Si es < n, entonces obtienes el personaje que pediste.
    • "De lo contrario" (es decir, si es n ), entonces obtienes charT() (es decir, el carácter nulo).

Pero no se define ninguna regla para cuando se rompe la condición previa, y la verificación de = n puede cumplirse implícitamente (pero no tiene el mandato explícito de hacerlo) almacenando realmente un charT() en la posición n .

Por lo tanto, las implementaciones no necesitan realizar ninguna comprobación de límites ... y las comunes no lo hacen.


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

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

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

Si bien esto puede parecer una verificación de límites, en la práctica, lo que realmente sucede es que std::basic_string asigna un búfer uno más grande que el solicitado y completa 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 el estándar no lo exige, no podría convencerme de que existe una alternativa. Había algo molesto con .data() que hacía difícil evitar el búfer único.


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 ninguna comprobación de límites.

(Énfasis mío).

Si desea verificar los límites, use std::basic_string::at

El estándar implica que la implementación debe proporcionar verificación de límites porque básicamente describe lo que hace un acceso de matriz no comprobado.

Si accede dentro de límites, se define. Si sales, provocas un comportamiento indefinido.