que new c++ memory-management overloading standards new-operator

c++ - que - new int en c



¿Por qué es:: operator new[] necesario cuando:: operator new es suficiente? (5)

Creo que ::operator new[] puede haber sido útil para sistemas bastante especializados donde los arrays "grandes pero pocos" podrían ser asignados por un asignador diferente que los objetos "pequeños pero numerosos". Sin embargo, actualmente es una especie de reliquia.

operator new puede razonablemente esperar que un objeto se construya en la dirección exacta devuelta, pero el operator new[] no puede. Los primeros bytes del bloque de asignación pueden usarse para una "cookie" de tamaño, la matriz puede inicializarse escasamente, etc. La distinción se vuelve más significativa para el operator new miembro operator new , que puede estar especializado para su clase particular.

En cualquier caso, ::operator new[] no puede ser muy esencial, porque std::vector (vía std::allocator ), que actualmente es la forma más popular de obtener matrices dinámicas, lo ignora.

En C ++ moderno, los asignadores personalizados son generalmente una mejor opción que el operator new personalizado operator new . En realidad, las new expresiones deben evitarse completamente a favor de las clases de contenedor (o puntero inteligente, etc.), que proporcionan más seguridad de excepción.

Como sabemos, el estándar C ++ define dos formas de funciones de asignación global:

void* operator new(size_t); void* operator new[](size_t);

Y también, el borrador del estándar de C ++ (18.6.1.2 n3797) dice:

227) No es responsabilidad directa del operador nuevo u operador borrar tener en cuenta el conteo de repetición o el tamaño del elemento de la matriz. Esas operaciones se realizan en otro lugar en el array new y delete expressions. La nueva expresión de matriz, sin embargo, puede aumentar el argumento de tamaño al operador nuevo para obtener espacio para almacenar información suplementaria.

Lo que me hace confundir es:

¿Qué pasa si eliminamos void* operator new[](size_t); del estándar, y simplemente usa void* operator new(size_t) lugar? ¿Cuál es la razón para definir una función de asignación global redundante?


El estándar (n3936) deja en claro que estos dos operadores tienen propósitos diferentes pero relacionados.

operator new llama a la función void* operator new(std::size_t) . El primer argumento debe ser idéntico al argumento para el operador. Devuelve un bloque de almacenamiento adecuadamente alineado, y que puede ser algo mayor que el requerido.

operator new[] llama a la función void* operator new[](std::size_t) . El primer argumento puede ser más grande que el argumento proporcionado al operador, para proporcionar espacio de almacenamiento adicional si es necesario para la indexación de matrices. El implemento predeterminado para ambos es simplemente llamar a malloc ().

El propósito del operator new[] es admitir indexación de matriz especializada, si está disponible. No tiene nada que ver con las agrupaciones de memoria o cualquier otra cosa. En una implementación conforme que hizo uso de esta característica, la implementación establecería tablas especializadas en el espacio adicional y el compilador generaría código para instrucciones o llamadas a las rutinas de soporte de la biblioteca de la biblioteca que utilizaban esas tablas. El código C ++ que utiliza matrices y el no usar new [] fallará en esas plataformas.

No estoy personalmente al tanto de tal implementación, pero se asemeja al tipo de características requeridas para el soporte de ciertos mainframes (CDC, IBM, etc.) que tienen una arquitectura bastante diferente a los chips Intel o RISC que conocemos y amamos.

En mi opinión, la respuesta aceptada es incorrecta.

Para completar, el estándar (n3936 principalmente en S5.3.4) contiene lo siguiente.

  1. Una distinción entre asignar un ''objeto de matriz'' o ''un objeto de no matriz''
  2. Se hace referencia a la ''sobrecarga de asignación de matriz'', con la implicación de que podría necesitarse almacenamiento adicional y podría (de alguna manera) usarse para un conteo de repetición o tamaño de elemento.

No hay referencia a los grupos de memoria ni a ninguna sugerencia de que esto pueda ser una consideración.


Estoy seguro de que hay casos de uso adecuados que requieren new[] y new , pero aún no he encontrado uno que sea excepcionalmente posible con esta separación y nada más.

Sin embargo, lo veo así: dado que el usuario llama a new versiones de operador new , el estándar de C ++ habría sido culpable de perder deliberada y deliberadamente información si hubieran definido un solo operator new y tenían new y new[] hacia adelante allí . Hay (literalmente) un poco de información aquí, que podría ser útil para alguien , ¡y no creo que la gente en el comité pueda haberlo rechazado con buena conciencia!

Además, tener que implementar el extra new[] es un inconveniente muy leve para el resto de nosotros, en todo caso, así que el intercambio de preservar un solo bit de información gana frente a tener que implementar una única función simple en una pequeña fracción de nuestros programas


::operator new[] y ~ delete[] facilitan la depuración del uso de la memoria, siendo un punto central para auditar las operaciones de asignación y desasignación; luego puede asegurarse de que el formulario de matriz se use para ambos o para ninguno.

También hay muchos usos plausibles si la sintonización muy inusual / crudo:

  • asignar matrices de un grupo separado, tal vez porque esa caché media mejorada crucialmente golpea para pequeños objetos asignados dinámicamente de un solo objeto,

  • diferentes sugerencias de acceso a la memoria (ala madvise ) para datos de matriz / no matriz

Todo eso es un poco extraño y fuera de las preocupaciones cotidianas del 99.999% de los programadores, pero ¿por qué evitar que sea posible?


El lenguaje de programación C ++: edición especial p 423 dice

_Las funciones operator new() y operator delete() permiten que un usuario asuma la asignación y desasignación de objetos individuales; operator new[]() y operator delete[]() cumplen exactamente la misma función para la asignación y desasignación de matrices.

Gracias Tony D por corregir mi malentendido de este matiz.

Wow, no es a menudo que estoy atrapado en algo en C ++. Estoy tan seguro de ... ¡Debo haber pasado demasiado tiempo en Objective-C!

respuesta incorrecta original

Es simple: la nueva forma [] invoca el constructor en cada elemento de una matriz C clásica.

Por lo tanto, primero asigna el espacio para todos los objetos, luego itera llamando al constructor para cada ranura.