¿Por qué no hay funcionalidad de reasignación en los asignadores de C++?


En C las funciones de manejo de memoria estándar son malloc(), realloc() y free(). Sin embargo, los asignadores stdlib de C++ solo son paralelos a dos de ellos: no hay una función de reasignación. Por supuesto, no sería posible hacer exactamente lo mismo que realloc(), porque simplemente copiar memoria no es apropiado para tipos no agregados. Pero habría un problema con, digamos, esta función:

bool reallocate (pointer ptr, size_type num_now, size_type num_requested);

Donde

  • ptr se asigna previamente con el mismo asignador para num_now objetos;
  • num_requested >= num_now;

Y la semántica como sigue:

  • si el asignador puede expandir el bloque de memoria dado en ptr desde el tamaño de los objetos num_now a los objetos num_requested, lo hace (dejando memoria adicional sin inicializar) y devuelve true;
  • de lo contrario no hace nada y devuelve false.

De acuerdo, esto no es muy simple, pero los asignadores, según tengo entendido, están destinados principalmente a contenedores y el código de contenedores generalmente es complicado ya.

Dada tal función, std::vector, digamos, podría crecer de la siguiente manera (pseudocódigo):

if (allocator.reallocate (buffer, capacity, new_capacity))
  capacity = new_capacity;     // That's all we need to do
else
  ...   // Do the standard reallocation by using a different buffer,
        // copying data and freeing the current one

Los asignadores que son incapaces de cambiar el tamaño de la memoria por completo podrían implementar tal función mediante return false; incondicional.

¿Hay tan pocas implementaciones de asignadores capaces de reasignación que no valdría la pena molestarse? ¿O hay algunos problemas que pasé por alto?

Author: doublep, 2010-06-23

5 answers

Desde: http://www.sgi.com/tech/stl/alloc.html

Este es probablemente el más cuestionable decisión de diseño. Habría probablemente ha sido un poco más útil para proporcionar una versión de reasignar que o bien cambió el tamaño de la objeto existente sin copiar o devuelto NULL. Esto lo habría hecho directamente útil para objetos con copia constructor. También habría evitar copias innecesarias en los casos en el que el objeto original no había ha sido completamente rellenado.

Desafortunadamente, esto tendría uso prohibido de realloc de la C biblioteca. Esto a su vez habría añadido complejidad a muchos asignador implementaciones, y habría hecho interacción con la memoria-depuración herramientas más difíciles. Así decidimos contra esta alternativa.

 18
Author: 5ound,
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
2010-06-23 21:41:26

Esto es en realidad un defecto de diseño que Alexandrescu señala con los asignadores estándar (no operador new []/delete [] pero lo que fueron originalmente los asignadores stl utilizados para implementar std::vector, por ejemplo).

Un realloc puede ocurrir significativamente más rápido que un malloc, memcpy y free. Sin embargo, si bien el bloque de memoria real se puede cambiar de tamaño, también puede mover la memoria a una nueva ubicación. En este último caso, si el bloque de memoria consiste en no-PODs, todos los objetos tendrán que ser destruidos y copia-construido después del realloc.

Lo principal que la biblioteca estándar necesita para acomodar esto como una posibilidad es una función de reasignación como parte de la interfaz pública del asignador estándar. Una clase como std::vector ciertamente podría usarlo incluso si la implementación predeterminada es malloc el bloque de nuevo tamaño y liberar el viejo. Tendría que ser una función que es capaz de destruir y copiar-construir los objetos en la memoria, sin embargo, no puede tratar la memoria en una moda opaca si hizo esto. Hay un poco de complejidad involucrada allí y requeriría un poco más de trabajo de plantilla que puede ser la razón por la que se omitió de la biblioteca estándar.

Std:: vector<...> :: reserve is not sufficient: it addresses a different case where the size of the container can be anticipated. Para listas de tamaño verdaderamente variable, una solución realloc podría hacer que los contenedores contiguos como std:: vector sean mucho más rápidos, especialmente si puede lidiar con casos realloc donde el bloque de memoria se redimensionó con éxito sin ser movido, en cuyo caso puede omitir llamar a constructores de copia y destructores para los objetos en memoria.

 11
Author: stinky472,
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
2010-06-24 09:41:42

Lo que estás pidiendo es esencialmente lo que hace vector::reserve. Sin semántica de movimiento para objetos, no hay manera de reasignar la memoria y mover los objetos sin hacer una copia y destruir.

 8
Author: Mark Ransom,
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
2010-06-23 20:05:56

Debido a la naturaleza orientada a objetos de C++, y la inclusión de los varios tipos de contenedores estándar, creo que es simplemente que se puso menos énfasis en la gestión de memoria de dirección que en C. Estoy de acuerdo en que hay casos en los que un realloc() sería útil, pero la presión para remediar esto es mínima, ya que casi toda la funcionalidad resultante se puede obtener utilizando contenedores en su lugar.

 3
Author: tlayton,
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
2010-06-23 20:00:56

Supongo que esta es una de las cosas en las que dios se equivocó, pero yo era demasiado perezoso para escribir al comité de estándares.

Debería haber habido un realloc para las asignaciones de matrices:

p = renew(p) [128];

O algo así.

 1
Author: Pavel Radzivilovsky,
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
2010-06-23 19:55:04