¿Por qué C++ no admite matrices dinámicas en la pila? [closed]

8 minutos de lectura

avatar de usuario
orlp

En C99 esto era legal:

void f(size_t sz) {
    char arr[sz];
    // ...
}

Sin embargo, esto (matrices de pila de tamaño dinámico) se ha descartado en C++ y no ha visto un retorno en C++11.

AFAIK C++ se hizo teniendo en cuenta la compatibilidad con C, así que me preguntaba Debe haber algún muy buen argumento para no incluir esta característica útil, ¿verdad?

Todo lo que podía pensar era esto:

ventajas

  • Ahorro de memoria al permitir tamaños de matriz más inteligentes que deben estar en la pila (¿búferes temporales?).
  • Menos “punteros inteligentes” (o peor, introducción manual de errores delete []‘s) y asignaciones de montón lentas.
  • Compatibilidad con C99.

Contras

  • Permite a las personas asignar fácilmente arreglos demasiado grandes en la pila, lo que genera desbordamientos de pila difíciles de depurar.
  • Más complicado para los escritores de compiladores.

Entonces, ¿por qué no lo incluyeron cuando importaron otras características de C99?


Para evitar que esto se cierre como “subjetivo” o “no constructivo”, estoy buscando citas de los miembros del comité o enlaces a discusiones que hablen sobre el tema, con puntos de bonificación para un resumen rápido de SO, por supuesto.

En lugar de ver esto como un Ponis vs Hamsters discusión, verlo como una cuestión histórica, mero interés en las ventajas y desventajas que se consideraron (si es que se consideraron).


EDITAR: Como señaló James McNellis en los comentarios a continuación, C++ existía antes de que C99 estandarizara las matrices de longitud variable. Puede leer mi pregunta entonces como: “¿Por qué no lo agregaron y no lo agregarán?“.

  • No se ha “eliminado” porque nunca fue parte de C++.

    –James McNellis

    18 de septiembre de 2011 a las 1:06

  • Por cierto, esto me parece una pregunta clara con una respuesta definitiva. No parece subjetivo, y aunque el término ‘caído’ está un poco cargado y no es del todo exacto, creo que es un problema menor.

    – Omnifaro

    18 de septiembre de 2011 a las 1:11

  • Estoy un poco sorprendido de que a la gente le guste tanto cerrar “¿Por qué?” preguntas como “subjetivas”. EN MI HUMILDE OPINIÓN, mucho de mejor las preguntas en StackOverflow son de hecho las preguntas “Por qué”. (Mira aquí.) El hecho de que varias personas puedan tener varias conjeturas en cuanto a la respuesta no significa que no haya una respuesta correcta. Creo que la gente debería relajarse un poco y permitir que las preguntas como esta continúen, en lugar de cerrarlas en el acto solo porque ellos No puedo pensar en una respuesta objetiva. :\

    – usuario541686

    18 de septiembre de 2011 a las 1:17


  • El motivo de las preguntas de cierre es preservar la calidad del contenido en SO. De todas las preguntas de mierda que quedan, ¿cómo es este pregunta que genera tanta controversia? Solo déjalo abierto; es útil e interesante.

    – diez cuatro

    18 de septiembre de 2011 a las 1:24

  • Esta no es una mala pregunta porque es subjetiva, es mala porque es un duplicado. 🙂

    – Omnifaro

    18 de septiembre de 2011 a las 1:45

avatar de usuario
Nawaz

Creo que es porque C ++ proporciona soluciones superiores: std::vector<T> y std::array<T,N> (C++11); aunque este último no es dinámico como tal, pero es superior a las matrices sin procesar. Siempre puede saber el tamaño, sin importar qué función pase el vector o la matriz.

Dado que C no puede proporcionar estas soluciones, C99 creó la matriz de longitud variable (VLA). Tiene el mismo problema que las matrices normales: se descompone en un puntero al pasarlo a la función y ya no sabes el tamaño de la matriz.

Y como Florian Weimer preguntó aquí a comp.std.c++ que si C++ 0x permite VLA, ¿qué significaría el siguiente código?

int vla[n]; //n is known at runtime!
std::vector<decltype(vla)> v; //what does this mean?

¿Cómo va a funcionar el compilador? instanciar la plantilla de vector en tiempo de compilación cuando es tipo de argumento depende de n que se conoce en tiempo de ejecución?

  • Si usted -1 algo, es de buena educación decir por qué.

    – Omnifaro

    18 de septiembre de 2011 a las 1:25

  • @Downvoter: especifique el motivo para que otros y yo podamos saber por qué esta respuesta es tonta; y cómo se puede mejorar.

    – Nawaz

    18 de septiembre de 2011 a las 1:26


  • Esta es una respuesta válida, si no está de acuerdo, no solo vote negativamente a ciegas, sino que diga en los comentarios. Lea la información sobre herramientas del botón de voto negativo: “esta respuesta no sirve”. No estoy de acuerdo con eso en esta pregunta en particular.

    – orlp

    18 de septiembre de 2011 a las 1:27

  • No puse -1, pero no estoy de acuerdo con “las soluciones de C++ son superiores”: tal vez lo sean en muchos contextos. Pero después de haber perfilado cuidadosamente un fragmento de código que tuve que escribir recientemente, las únicas opciones sensatas eran un vector estático o la extensión VLA de gcc, para evitar asignaciones de montón demasiado frecuentes. Elegí vector para la portabilidad, pero esto me dejó con una función no segura para subprocesos (que está esperando la implementación de “thread_local”). En este caso, no era necesario saber el tamaño fuera de la función, y VLA estaba superior a std::array (por cierto, no podía entender por qué std::array era tan lento que VLA).

    – rafak

    18 de septiembre de 2011 a las 12:24


  • @Nawaz: std::vector<T> inicializa sus elementos, lo que puede incurrir en un impacto de rendimiento inaceptable en algunos casos. los decltype el problema es una pista falsa; el compilador simplemente podría rechazarlo, al igual que el compilador Objective-C++: Variably modified type 'decltype(a)' (aka 'int [n]') cannot be used as a template argument.

    – Marcelo Cantos

    4 de mayo de 2013 a las 5:44


avatar de usuario
bdonlan

Esta funcionalidad duplica en gran medida la de std::vector, excepto que consume un recurso más limitado (pila frente a espacio de montón). Como tal, no hay realmente ninguna necesidad de ello en C++, en cuanto a la semántica.

Se podría argumentar que la asignación en la pila puede mejorar la eficiencia (particularmente frente a múltiples subprocesos); sin embargo, esto también se puede lograr en C++ usando asignadores personalizados para crear un grupo de memoria privado, ya sea en la pila o en el montón. Nuevamente, esto es más flexible que colocar memoria en la pila y, de hecho, podría crear un asignador personalizado que extraiga fragmentos de un búfer de memoria en la pila con bastante facilidad. No es exactamente lo mismo que la semántica de matriz dinámica, pero la existencia de asignadores personalizados y contenedores STL cubre la mayoría de los casos de uso en los que desearía una asignación de pila.

  • ¿Hubo una discusión en ese sentido? Una cosa que me viene a la mente es que el espacio de la pila es automáticamente local al subproceso, y eso puede ser muy útil porque hace que la asignación del espacio de la pila sea muy rápida en comparación con la asignación del espacio del montón en muchas implementaciones. Pero puedo entender si ese hecho fue considerado y encontrado no convincente. Tengo curiosidad.

    – Omnifaro

    18 de septiembre de 2011 a las 1:24

  • @bdolan: el espacio de pila es la asignación de velocidad O(1), lo cual es excelente para cosas como nombres de archivos (que tienen alrededor de ~ 256 caracteres máximo). Las asignaciones de montón son comparativamente mucho más lento, y las aplicaciones que funcionan con cadenas pequeñas a menudo podrían beneficiarse enormemente al usar el primero en lugar del segundo. Así que personalmente no estoy convencido de que no haya una “necesidad” en C++. (De lo contrario, ¿por qué los compiladores implementan _alloca ¿tan a menudo?)

    – usuario541686

    18 de septiembre de 2011 a las 1:26


  • No sé si esto realmente se discutió en el proceso de estandarización, pero parece una razón razonable para excluirlo. Sí, la asignación local puede ser marginalmente más eficiente, pero muchas implementaciones de malloc tienen grupos locales de subprocesos de todos modos, y para asignaciones más grandes, el costo de construcción excede el de la asignación de todos modos.

    – bdonlan

    18 de septiembre de 2011 a las 1:28

  • @Mehrdad, std::string las implementaciones a menudo tienen pequeñas cadenas asignadas dentro del objeto de todos modos …

    – bdonlan

    18 de septiembre de 2011 a las 1:28

  • @Mehrdad: Visual C++ 2010 std::string La implementación utiliza la optimización de cadenas pequeñas.

    –James McNellis

    18 de septiembre de 2011 a las 1:52

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad