c++ memory-management c++11 allocator

c++ - ¿Por qué se está eliminando la referencia de Allocator::?



memory-management c++11 (3)

Así que estaba buscando en la especificación de std::vector y noté que typedef de reference cambió de Allocator::reference en C ++ 03 a value_type& en C ++ 11. Me sorprendió, así que comencé a buscar más profundamente.

En C ++ 03 §20.1.5 [lib.allocator.requirements] hay una tabla 32 en la que X::reference se define como T& y X::const_reference se define como T const& .

Sin embargo, en C ++ 11 §17.6.3.5 [allocator.requirements] hay una tabla 28 en la que faltan la reference y la reference .

A continuación tenemos §20.6.8 std::allocator_traits agregado en C ++ 11 que no incluye reference . Pero §20.6.9 std::allocator does.

Finalmente, hay §23.2.1 [container.requirements.general] que define X::reference como "lvalue of T " y X::const_reference como "const lvalue of T ".

Entonces, busqué en Google y encontré este documento ( 1 , 2 ) que propone la eliminación de la reference de los requisitos del asignador, pero no menciona ningún fundamento detrás de esto. Pero también hay un problema de LWG que se opone al cambio.

Además, encontré la entrevista con Alexander Stepanov en la que habla cómo la reference encapsula el diseño de la memoria específica de la máquina y la publicación de Herb Sutter en la que habla sobre cómo tomar punteros a los elementos del contenedor, requisitos del contenedor y cómo std::vector<bool> es no es un contenedor

Entonces, ¿qué piensas de todo esto? ¿La reference fue útil, sirvió para su propósito? ¿Cómo encajan las referencias "sofisticadas" en el Estándar? ¿Es esto un movimiento audaz para eliminarlos por completo, hacer requisitos de contenedores más estrictos y depreciar std::vector<bool> ?


En la entrevista con Alexander Stepanov , menciona que durante la propuesta de agregar STL a la biblioteca estándar se le pidió que creara una abstracción a partir del modelo de memoria. Por lo tanto, nacieron los asignadores. En el tema LWG hay un ejemplo de implementación donde la reference del asignador personalizado se define como T __far& .

Pero, por razones desconocidas porque no tengo mucho tiempo para buscar, el estándar C ++ 03 tiene el siguiente texto en §20.1.5 p4:

Las implementaciones de los contenedores descritos en este Estándar Internacional pueden suponer que su parámetro de plantilla de Allocator cumple con los siguientes dos requisitos adicionales más allá de los indicados en la Tabla 32.

- Se requiere que todas las instancias de un tipo de asignador determinado sean intercambiables y siempre se comparen entre sí.

- Se requiere que los punteros de los miembros typedef, const_pointer, size_type, y difference_type sean T *, T const *, size_t y ptrdiff_t, respectivamente.

Esto efectivamente anula la capacidad del asignador de modelo de memoria personalizado para interoperar con contenedores estándar.

Durante mi búsqueda de todos los documentos anteriores a C ++ 11 que mencionan la palabra "asignador", he encontrado un gran consenso para eliminar esas palabras del Estándar. Finalmente, 2 propone eliminarlos con el siguiente comentario:

Las palabras de comadreja se han ido. Levanta tu vaso y haz un brindis.

¿Victoria? ¿Podemos finalmente volvernos salvajes con nuestros modelos de memoria? No tanto. Entre otras cosas, el mismo documento propone eliminar la reference de los requisitos del asignador. Y parece que fue votado en el estándar.

El problema de LWG que mencioné antes se opone al cambio, pero se cerró con la siguiente declaración:

Sin consenso para hacer un cambio

Por lo tanto, parece que el propósito original de los asignadores no es tan importante en la actualidad. Esto es lo que Wikipedia tiene que decir:

El propósito actual de los asignadores es dar al programador el control sobre la asignación de memoria dentro de los contenedores, en lugar de adaptar el modelo de dirección del hardware subyacente. De hecho, el estándar revisado eliminó la capacidad de los asignadores para representar extensiones del modelo de dirección C ++, eliminando formal y deliberadamente su propósito original.

Finalmente, la Container::reference no tiene nada que ver con los asignators. Fue creado para permitir colecciones proxy que en realidad no son contenedores . Así que está aquí para quedarse. Por cierto, parece que es otro ejemplo de cómo las palabras finales en el Estándar van en contra de las intenciones originales.


Porque ese typedef anidado es superfluo. STL efectivo de Scott Meyers , página 49:

el Estándar explícitamente permite a los implementadores de bibliotecas suponer que el puntero de cada asignador typedef es un sinónimo para T * y el typedef de referencia de cada asignador es lo mismo que T &


http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)

"Originalmente fueron pensados ​​como un medio para hacer que la biblioteca fuera más flexible e independiente del modelo de memoria subyacente, permitiendo a los programadores utilizar punteros personalizados y tipos de referencia con la biblioteca. Sin embargo, en el proceso de adopción de STL en el estándar C ++, el C ++ El comité de normalización se dio cuenta de que una abstracción completa del modelo de memoria incurriría en penalizaciones de rendimiento inaceptables. Para remediar esto, los requisitos de los asignativos se volvieron más restrictivos. Como resultado, el nivel de personalización proporcionado por los asignadores es más limitado de lo que originalmente Stepanov "

Originalmente fueron diseñados para abstraer la memoria , permitiéndole a uno asignar memoria en, por ejemplo, otra máquina a través de una conexión a Internet, y copiar datos hacia adelante y hacia atrás utilizando punteros / referencias para hacer un seguimiento de lo que está activo. Del mismo modo, uno podría hacer un GC similar a Java en C ++ puro. ¡Esta abstracción parecía una idea increíble!

Sin embargo, esto incurrió en penalizaciones de rendimiento que se consideraron inaceptables en ese momento. Además, si lo piensas, es casi imposible trabajar en código. Cada void func(const string&) tendría que hacerse en una template<class allocator> void func(allocator::reference) , que es un contexto no deducible, por lo que tendría que escribir explícitamente el asignador en la llamada de función ( func<std::allocator<std::string>::const_reference>(username) ), que nadie haría, lo que haría que el GC no funcionara correctamente. Hoy en día, los asignadores simplemente resumen la asignación / desasignación de memoria.