En C++ 2003, el modelo del asignador está roto y no hay realmente una solución adecuada. Para C++ 2011, el modelo del asignador fue corregido y puede tener asignadores por instancia que se propagan a objetos contenidos (a menos que, por supuesto, elija reemplazarlos). Generalmente, para que esto sea útil, probablemente desee utilizar un tipo de asignador dinámicamente polimórfico que no se requiere que sea el predeterminado std::allocator<T>
(y generalmente esperaría que no fuera dinámicamente polimórfico, aunque esta podría ser la mejor opción de implementación). Sin embargo, [casi] todas las clases de la biblioteca estándar de C++ que asignan memoria son plantillas que toman el tipo de asignador como argumento de plantilla (por ejemplo, IOStreams son una excepción, pero generalmente no asignan ninguna cantidad interesante de memoria para justificar agregar soporte de asignador)
En varios de sus comentarios insiste en que los asignantes efectivamente deben ser globales: eso definitivamente no es correcto. Cada tipo de asignador almacena una copia del asignador dado (al menos, si tiene datos de nivel de instancia, si no hay nada que almacenar como es, por ejemplo, el caso con el asignador predeterminado usando operator new()
y operator delete()
) . Esto significa efectivamente que el mecanismo de asignación otorgado a un objeto debe mantenerse mientras exista un asignador activo que lo use. Este puede hacerse usando un objeto global, pero también se puede hacer usando, p. recuento de referencia o asociación del asignador con un objeto que contiene todos los objetos a los que está asignado. Por ejemplo, si cada "documento" (piense XML, Excel, Pages, cualquier archivo de estructura) pasa un asignador a sus miembros, el asignador puede vivir como miembro del documento y destruirse cuando el documento se destruye después de que se destruye todo su contenido . Esta parte del modelo de asignador debería funcionar con clases anteriores a C++ 2011, siempre que también tomen un argumento de asignación. Sin embargo, en las clases anteriores a C++ 2011, el asignador no se pasará a los objetos contenidos. Por ejemplo, si asigna un asignador a std::vector<std::string>
, la versión de C++ 2011 creará el std::string
utilizando el asignador asignado al std::vector<std::string>
debidamente convertido para ocuparse de std::string
s.Esto no sucederá con los asignadores anteriores a C++ 2011.
Para utilizar realmente los asignadores en un subsistema, deberá pasarlos de manera explícita, ya sea explícitamente como argumento para sus funciones y/o clases o implícitamente por medio de objetos que reconocen el asignador que sirven como contexto. Por ejemplo, si usa cualquiera de los contenedores estándar como [parte del] contexto pasado, puede obtener el asignador usado utilizando su método get_allocator()
.
¿Por qué un asignador debe ser global? Siempre que cada unidad asignada tenga una referencia a su propio asignador para que pueda liberarse correctamente, ¿qué importancia tiene el asignador en realidad? –
Sin embargo, ¿dónde se iría el asignador para la unidad asignada? Me parece que debería ser global. – chadb