Me topé con un cuestionario que involucraba una declaración de matriz con diferentes tamaños. Lo primero que me vino a la mente es que necesitaría usar una asignación dinámica con el new
comando, así:
while(T--) {
int N;
cin >> N;
int *array = new int[N];
// Do something with 'array'
delete[] array;
}
Sin embargo, vi que una de las soluciones permitía el siguiente caso:
while(T--) {
int N;
cin >> N;
int array[N];
// Do something with 'array'
}
Después de un poco de investigación, leí que g ++ permite esto, pero me mantuvo pensando, ¿en qué casos es necesario usar la asignación dinámica? ¿O es que el compilador traduce esto como asignación dinámica?
La función de eliminación está incluida. Sin embargo, tenga en cuenta que la pregunta aquí no se trata de pérdidas de memoria.
c++
arrays
dynamic-memory-allocation
static-memory-allocation
aprendizaje_dude
fuente
fuente
std::vector
en su lugar (std::vector<int> array(N);
).new OBJ
directamente.Respuestas:
Ninguno de los fragmentos que muestra es un código C ++ idiomático y moderno.
new
ydelete
(ynew[]
ydelete[]
) no están en desuso en C ++ y nunca lo estarán. Todavía son la forma de instanciar objetos asignados dinámicamente. Sin embargo, como siempre debe hacer coincidir anew
con adelete
(y anew[]
con adelete[]
), es mejor guardarlos dentro de las clases (de la biblioteca) que garanticen esto. Consulte ¿Por qué los programadores de C ++ deberían minimizar el uso de 'nuevo'? .Su primer fragmento utiliza un "desnudo"
new[]
y luego nuncadelete[]
es la matriz creada. Eso es un problema.std::vector
hace todo lo que necesitas aquí bien. Utilizará alguna forma denew
detrás de escena (no me sumergiré en los detalles de implementación), pero por lo que debe preocuparse, es una matriz dinámica pero mejor y más segura.Su segundo fragmento utiliza "matrices de longitud variable" (VLA), una característica de C que algunos compiladores también permiten en C ++ como una extensión. A diferencia
new
, los VLA se asignan esencialmente en la pila (un recurso muy limitado). Pero lo más importante, no son una característica estándar de C ++ y deben evitarse porque no son portátiles. Ciertamente no reemplazan la asignación dinámica (es decir, el montón).fuente
Qt
, ya que todas sus clases base tienen recolectores de basura, por lo que solo debe usarlonew
y olvidarse de él la mayor parte del tiempo. Para los elementos de la GUI, cuando el widget primario está cerrado, los secundarios quedan fuera del alcance y se recolectan basura automáticamente.new
tiene una coincidenciadelete
; es solo que lasdelete
s las realiza el widget principal en lugar del mismo bloque de código que lasnew
s.Bueno, para empezar,
new
/delete
no están siendo obsoleta.Sin embargo, en su caso específico, no son la única solución. Lo que elija depende de lo que se ocultó en su comentario de "hacer algo con la matriz".
Su segundo ejemplo utiliza una extensión VLA no estándar que intenta ajustar la matriz en la pila. Esto tiene ciertas limitaciones, a saber, el tamaño limitado y la imposibilidad de usar esta memoria después de que la matriz se salga del alcance. No puede moverlo, "desaparecerá" después de que la pila se desenrolle.
Entonces, si su único objetivo es hacer un cálculo local y luego descartar los datos, en realidad podría funcionar bien. Sin embargo, un enfoque más sólido sería asignar la memoria dinámicamente, preferiblemente con
std::vector
. De esa manera, obtienes la capacidad de crear espacio para exactamente tantos elementos como necesites basándose en un valor de tiempo de ejecución (que es lo que vamos a hacer todo el tiempo), pero también se limpiará muy bien y podrás moverlo de este alcance si desea mantener la memoria en uso para más adelante.Dando vueltas de nuevo al principio,
vector
será probablemente utilizarnew
unas pocas capas más profundas, pero no debe preocuparse por eso, como la interfaz que presenta es muy superior. En ese sentido, usarnew
ydelete
puede considerarse desalentado.fuente
new
ydelete
, sino usar punteros inteligentes comostd::unique_pointer
.std::unique_ptr
std::unique_ptr
llamadas destructor predeterminadasdelete
odelete[]
, lo que significa que el objeto de propiedad debe haber sido asignado pornew
o denew[]
todos modos, qué llamadas han estado ocultasstd::make_unique
desde C ++ 14.Su segundo ejemplo utiliza matrices de longitud variable (VLA), que en realidad son una función C99 (¡ no C ++!), Pero que sin embargo es compatible con g ++ .
Ver también esta respuesta .
Tenga en cuenta que las matrices de longitud variable son diferentes de
new
/delete
y no las "desprecian" de ninguna manera.También tenga en cuenta que los VLA no son ISO C ++.
fuente
Modern C ++ proporciona formas más fáciles de trabajar con asignaciones dinámicas. Los punteros inteligentes pueden encargarse de la limpieza después de las excepciones (que pueden ocurrir en cualquier lugar si se permite) y los retornos anticipados, tan pronto como las estructuras de datos referenciadas salgan del alcance, por lo que puede tener sentido usar estas en su lugar:
Desde C ++ 14 también puedes escribir
esto se ve aún mejor y evitaría la pérdida de memoria si falla la asignación. Desde C ++ 20 deberías poder hacer tanto como
esto para mí todavía no se compila al momento de escribir con gcc 7.4.0. En estos dos ejemplos también usamos en
auto
lugar de la declaración de tipo a la izquierda. En todos los casos, use la matriz como de costumbre:La pérdida de memoria
new
y los bloqueos por duplicacióndelete
es algo que C ++ ha sido criticado durante muchos años, siendo el "punto central" de la argumentación para cambiar a otros lenguajes. Quizás sea mejor evitarlo.fuente
unique/shared_ptr
constructores a favormake_unique/shared
, no solo no tiene que escribir el tipo construido dos veces (usandoauto
) sino que no corre el riesgo de perder memoria o recursos si la construcción falla a la mitad (si está usando un tipo que puede fallar)make_shared<int[]>
mucho, cuando casi siempre quieresvector<int>
, pero es bueno saberlo.unique_ptr
constructor no es arrojar, por loT
que no tienen constructores, por lo que no hay riesgo de fugasunique_ptr(new int[size])
yshared_ptr
tiene lo siguiente: "Si se produce una excepción, se llama a p cuando T no es un tipo de matriz, eliminar [ ] p de otro modo ", por lo que tiene el mismo efecto -. el riesgo es paraunique/shared_ptr(new MyPossiblyAllocatingType[size])
.new y delete no se están desaprobando.
Los objetos creados por el nuevo operador se pueden pasar por referencia. Los objetos se pueden eliminar con eliminar.
nuevo y eliminar son los aspectos fundamentales del lenguaje. La persistencia de un objeto se puede administrar usando new y delete. Definitivamente, estos no serán desaprobados.
La declaración - int array [N] es una forma de definir una matriz. La matriz se puede usar dentro del alcance del bloque de código adjunto. No se puede pasar como cómo se pasa un objeto a otra función.
fuente
El primer ejemplo necesita un
delete[]
al final, o tendrá una pérdida de memoria.El segundo ejemplo usa una longitud de matriz variable que no es compatible con C ++; que sólo permite constante-expresión para longitud de la matriz .
En este caso es útil usarlo
std::vector<>
como solución; que envuelve todas las acciones que puede realizar en una matriz en una clase de plantilla.fuente
La sintaxis se parece a C ++, pero el idioma es similar al antiguo Algol60. Era común tener bloques de código como este:
El ejemplo podría escribirse como:
A veces extraño esto en los idiomas actuales;)
fuente