¿qué tan portátil es el decremento del iterador final?


Acaba de encontrar decremento de end() iterador en los códigos fuente de mi empresa y se ve extraño para mí. Por lo que recuerdo, esto estaba funcionando en algunas plataformas, pero no para las otras. Tal vez me equivoque, sin embargo, no pude encontrar nada útil en standard sobre eso. Standard solo dice que end() devuelve un iterador que es el valor pasado al final, pero ¿está garantizado que sea decrementable? ¿Cómo un código como ese coincide con el estándar?

std::list<int>::iterator it = --l.end();

Gracias de antemano.

Author: ledokol, 0000-00-00

1 answers

Creo que esta es la cláusula relevante:{[18]]}

ISO / IEC 14882: 2003 C++ Standard 23.1.1 / 12-Sequences

El cuadro 68 enumera las operaciones de secuencia que se proporcionan para algunos tipos de contenedores secuenciales pero no otros. Una aplicación deberá proporcionar estos operaciones para todos los tipos de contenedores se muestra en la columna "contenedor", y los ejecutará de manera que: tiempo constante amortizado.

    +----------------------------------------------------------------------------+
    |                                  Table 68                                  |
    +--------------+-----------------+---------------------+---------------------+
    |  expression  |   return type   |     operational     |      container      |
    |              |                 |      semantics      |                     |
    +--------------+-----------------+---------------------+---------------------+
    | a.front()    | reference;      | *a.begin()          | vector, list, deque |
    |              | const_reference |                     |                     |
    |              | for constant a  |                     |                     |
    +--------------+-----------------+---------------------+---------------------+
    | a.back()     | reference;      | *--a.end()          | vector, list, deque |
    |              | const_reference |                     |                     |
    |              | for constant a  |                     |                     |
    ..............................................................................
    .              .                 .                     .                     .
    .              .                 .                     .                     .
    ..............................................................................
    | a.pop_back() | void            | a.erase(--a.end())  | vector, list, deque |
    ..............................................................................
    .              .                 .                     .                     .
    .              .                 .                     .                     .

Así que para los contenedores listed, no solo debe el iterador devuelto desde end() ser decrementable, el iterador decrementado también debe ser desreferenciable. (A menos que el contenedor esté vacío, por supuesto. Eso invoca un comportamiento indefinido.)

De hecho, vector, list y deque las implementaciones que vienen con el compilador de Visual C++ lo hacen exactamente igual que la tabla. Por supuesto, eso no implica que cada compilador lo haga así:

// From VC++'s <list> implementation

reference back()
    {    // return last element of mutable sequence
    return (*(--end()));
    }

const_reference back() const
    {    // return last element of nonmutable sequence
    return (*(--end()));
    }

Nota sobre el código en la tabla:

ISO/IEC 14882:2003 Norma C++ 17.3.1.2 / 6-Requisitos

En algunos casos la semántica los requisitos se presentan como C + + codificar. Dicho código pretende ser un especificación de la equivalencia de un construir a otro construir , no necesariamente como la forma en que la construcción debe aplicarse.

Así que si bien es cierto que una implementación puede no implementar esas expresiones en términos de begin() y end(), el estándar de C++ especifica que las dos expresiones son equivalentes. En otras palabras, a.back() y *--a.end() son construcciones equivalentes según la cláusula anterior. Me parece que significa que usted debe ser capaz de reemplazar cada instancia de a.back() con *--a.end() y viceversa y tener el código todavía funciona.


Según Bo Persson, la revisión del estándar de C++ que tengo a mano tiene un defecto con respecto a la Tabla 68.

Proyecto de resolución:

Cambiar la especificación del cuadro 68 "Operaciones de Secuencia Opcionales" en 23.1.1 / 12 para "a.back()" de

*--a.end()

A

{ iterator tmp = a.end(); --tmp; return *tmp; }

Y la especificación para "a. pop_back ()" de

a.erase(--a.end())

A

{ iterator tmp = a.end(); --tmp; a.erase(tmp); }

Parece que todavía puede decrementar el iterador devuelto desde end() y desreferenciar el iterador decrementado, siempre y cuando no sea temporal.

 47
Author: ,
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
2011-03-16 21:52:01