punteros - operador new c++
¿Cuál es la ventaja de usar std:: allocator en lugar de nuevo en C++? (7)
En mi opinión, es más complicado usarlo en lugar de usar new y delete.
Sí, pero no está destinado a reemplazar
new
y
delete
, tiene un propósito diferente.
Con el asignador debemos asignar explícitamente memoria de montón, construirla, destruirla y finalmente desasignar la memoria.
Entonces, ¿por qué se creó?
Porque a veces desea separar la asignación y la construcción en dos pasos (y de manera similar, separar la destrucción y la desasignación en dos pasos).
Si no desea hacer eso, no use un asignador, use
new
lugar.
¿En qué casos se puede usar y cuándo se debe usar en lugar de nuevo y eliminar?
¡Cuando necesita el comportamiento de un asignador, no el comportamiento de
new
y
delete
, obviamente!
El caso típico es cuando se implementa un contenedor.
Considere el siguiente código:
std::vector<X> v;
v.reserve(4); // (1)
v.push_back( X{} ); // (2)
v.push_back( X{} ); // (3)
v.clear(); // (4)
Aquí la línea (1) debe asignar suficiente memoria para cuatro objetos, pero no construirlos todavía. Luego, las líneas (2) y (3) deben construir objetos en la memoria asignada. Entonces la línea (4) debe destruir esos objetos, pero no desasignar la memoria. Finalmente, en el destructor del vector, toda la memoria se puede desasignar.
Por lo tanto, el vector no puede simplemente usar la
new X()
o
delete &m_data[1]
para crear y destruir los objetos, sino que debe realizar la asignación / desasignación por separado de la construcción / destrucción.
El argumento de la plantilla del asignador de un contenedor define la política que se debe usar para (des) asignar memoria y construir / destruir objetos, lo que permite personalizar el uso de la memoria del contenedor.
La política predeterminada es el tipo
std::allocator
.
Por lo tanto, usa un asignador cuando se requiere un asignador (como cuando se usa un contenedor) y usa
std::allocator
cuando no desea proporcionar un asignador personalizado y solo desea el estándar.
No utiliza un asignador como reemplazo de
new
y
delete
.
Acabo de leer sobre
std::allocator
.
En mi opinión, es más complicado usarlo en lugar de usar
new
y
delete
.
Con el
allocator
debemos asignar explícitamente memoria de montón, construirla, destruirla y finalmente desasignar la memoria.
Entonces, ¿por qué se creó?
¿En qué casos se puede usar y cuándo se debe usar en lugar de nuevo y eliminar?
El
std::allocator
fue creado para permitir a los desarrolladores un mayor control de cómo se asigna la memoria.
En muchos sistemas integrados, la memoria está limitada y en diferentes tipos.
Puede que no haya una gran cantidad.
Además, la asignación de memoria quiere minimizarse para evitar problemas de fragmentación.
El asignador también permite la asignación de diferentes grupos de memoria. Entonces, por ejemplo, la asignación de bloques de pequeño tamaño sería más eficiente desde un grupo de memoria de bloques pequeños.
La razón de este miembro STL es dar al desarrollador más control sobre la memoria. Lo que quiero decir con esto es, por ejemplo, que el nuevo operador no es realmente una sola operación per se. En su forma más básica, realiza una reserva de memoria Y luego llena ese espacio con el objeto.
Aunque no puedo pensar en un escenario de caso específico del mundo real, debe usar
std::allocator
y tal vez cuando, tal vez, la destrucción de un objeto determinado pueda afectar a otros objetos en la memoria.
Digamos que, en aras de la discusión, creó algún tipo de vector en el que cada elemento está doblemente vinculado a algún otro objeto en la memoria y desea, en el momento de la eliminación de dicho vector, los objetos vinculados para eliminar la referencia de nuevo a eso.
Las asignaciones son un concepto muy importante en el STL. Cada contenedor es capaz de tomar un asignador como argumento. Luego, las asignaciones se realizarán utilizando este asignador, y no el estándar.
Esto es útil, por ejemplo, para asignar objetos del mismo tamaño en un grupo, para mejorar el rendimiento, o podría ser necesario si hay un área especial de memoria donde sus objetos necesitan vivir.
Los pasos de asignación y construcción están separados porque, por ejemplo, para el vector (
std::vector::reserve
) es importante poder asignar memoria para uso futuro, pero no (todavía) crear objetos allí.
Como example , podría escribir un asignador como una clase, que contenga una matriz de tamaño fijo, y usar esa matriz para proporcionar memoria para algún contenedor estándar. Entonces puede tener una instancia de esa clase en la pila y así evitar por completo las asignaciones de montón para alguna parte de su programa.
Vea más ejemplos aquí en esta publicación SO.
[...] Cuándo debería usarse [...]
Cuando tenga necesidades específicas, y lo más importante al escribir contenedores genéricos propios.
Tu instinto es correcto.
En el 90% de los casos, use
new
.
Sin embargo, observe en estructuras como, por ejemplo, la estructura de datos del
map
.
Uno de sus argumentos de plantilla predeterminados es
class Alloc = allocator<pair<const Key,T>
, que define cómo la clase crea nuevas instancias de cosas y gestiona instancias existentes.
De esta manera, teóricamente podría crear su propio asignador y luego usarlo para las estructuras de datos existentes.
Dado que
new
y
delete
son funciones y no clases, es necesario tener el
std::allocator
para representarlos y hacerlos argumentos de plantilla válidos.
new
y
delete
son la forma directa de crear un objeto en la memoria dinámica e inicializarlo.
Sin embargo, los asignadores son mucho más, porque ofrecen un control completo sobre las fases antes mencionadas.
Con el asignador debemos asignar explícitamente memoria de montón, construirla, destruirla y finalmente desasignar la memoria.
De hecho, no se supone que los asignadores se usen para el código "normal" donde
new
y
delete
también estarían bien.
Considere una clase como
std::map
, a menudo implementada como un árbol: ¿necesita desasignar toda la hoja cada vez que se elimina un objeto?
Los asignadores le permiten destruir ese objeto, pero conservan la memoria para que no tenga que volver a necesitarlo.
Además, puede especializar un asignador para un determinado tipo si conoce métodos más optimizados para su control que no es posible para
new
y
delete
.
std::allocator
es el asignador de memoria predeterminado para los contenedores de biblioteca estándar, y puede sustituir sus propios asignadores.
Esto le permite controlar cómo los contenedores estándar asignan memoria.
Pero no creo que su pregunta sea sobre
std::allocator
específicamente, sino más bien la estrategia de asignar memoria, luego construir objetos en esa memoria, en lugar de usar una
new T[N]
, por ejemplo.
Y la razón de esto es que la
new T[N]
no te permite controlar cómo se llaman los constructores.
Y te obliga a construir todos tus objetos al mismo tiempo.
Esto es terrible para los propósitos de, por ejemplo,
std::vector
donde solo desea asignar ocasionalmente.
Con un asignador de memoria sin procesar, puede asignar una cierta cantidad de memoria, que determina su capacidad. Luego, a medida que el usuario agrega elementos al vector (utilizando el constructor de su elección), puede construir objetos en su lugar en esta memoria.
Luego, cuando se queda sin memoria, asigna más, generalmente el doble.
Si
std::vector
usara una
new T[N]
, tendría que reasignarse cada vez que quisiera agregar o eliminar un elemento, lo que sería terrible para el rendimiento.
También se vería obligado a usar el constructor predeterminado para todos los objetos, lo que impone una restricción innecesaria sobre los tipos de objetos que
std::vector
puede contener.