2009-11-08 13 views
13

Por lo que entiendo, en C++ estándar cada vez que utiliza el nuevo operador también debe usar el operador de eliminación en algún momento para evitar pérdidas de memoria. Esto es porque no hay recolección de basura en C++. En .NET recolección de basura es automática, por lo que no hay necesidad de preocuparse por la gestión de memoria. Es mi entendimiento correcto? Gracias.¿La recolección de basura es automática en C++ estándar?

+9

¡Cien por ciento correcto! – henle

+10

99.9% correcto. Hay casos en los que debe preocuparse por la administración de la memoria en .NET. – jmucchiello

+1

en C++/CLI que asigna usando 'gcnew'; sin embargo, todavía puede usar 'nuevo', pero luego deben emparejarse con 'eliminar', al igual que en el código completamente no administrado. –

Respuesta

19

La larga respuesta a esto es que por cada vez que se llama new, en alguna parte, de alguna manera, delete debe ser llamado, o alguna otra función de cancelación de asignación (depende del asignador de memoria, etc.)

pero no es así tenga que ser el suministro de la llamada delete:

  1. hay recolección de basura para C++ en la forma de la Hans-Boehm Garbage Collector. También hay probablemente otras bibliotecas de recolección de basura.
  2. Puede usar punteros inteligentes, que usan RAII (y el recuento de referencias si el puntero permite el acceso compartido) para determinar cuándo eliminar el objeto. Una buena biblioteca de puntero inteligente es Boost smart pointer. Los punteros inteligentes en la gran mayoría de los casos pueden reemplazar los punteros sin formato.
  3. Algunos marcos de aplicaciones, como Qt, compilan árboles de objetos, de modo que existe una relación primaria parental para los objetos asignados de montón del marco.Como resultado, todo lo que se necesita es que se llame a un delete en un objeto, y todos sus hijos serán automáticamente delete d también.

Si no desea utilizar cualquiera de estas técnicas, para protegerse contra fugas Memoria, se pueden tratar de usar una memoria que controla la herramienta. Valgrind es particularmente bueno, aunque solo funciona en Linux

En cuanto a .NET, sí, la asignación mediante gcnew significa que la memoria está rastreada por .NET, por lo que no tiene fugas. Sin embargo, el GC no gestiona otros recursos, como manejadores de archivos, etc.

+6

Una de las ventajas (!) De RAII es que puede administrar recursos distintos de la memoria, p. manejadores de archivos Elimine el objeto y voila también se cierra el archivo propiedad del objeto. – casualcoder

+0

No te olvides de SBRM mientras estamos lanzando acrónimos. fstream, por ejemplo, cerrará automáticamente su archivo cuando salga del alcance. También recuerde que las variables miembro tienen un alcance de la vida del objeto principal, lo que hace que SBRM sea muy conveniente incluso sin un destructor. – joshperry

+1

Creo que el SBRM al que se refiere para fstream es RAII. – blwy10

0

Corregir usted tiene que preocuparse por la recolección de basura en C++.

Y ... hay no need to worry about garbage collection on .NET.

Solo si tiene scripts intensos y largos que necesita la optimización, necesita enfocarse en eso.

Edit: Ambos comentarios asveikau y Pavel Minaev son geniales, gracias! Sobregeneralicé para pasar el mensaje.

+0

No diría por completo que "no tiene que preocuparse por eso". Para algunos tipos de objetos, debes tener cuidado de realizar una limpieza manual, incluso en C#. Por ejemplo, debe asegurarse de cerrar archivos y no confiar en que GC lo haga por usted. – asveikau

+1

Y, por supuesto, nada le impide asignar memoria no administrada en C# (u otro lenguaje .NET), que luego tiene que liberar usted mismo. Consulte 'Marshal.AllocHGlobal', etc. –

1

"no hay recolección de basura en C++".

correcta.

+2

No es cierto. Hay recolectores de basura disponibles. (Y no es tan difícil de construir el suyo). –

+1

"disponible" o "una característica estándar del idioma?" La pregunta es acerca de las características estándar del lenguaje. No disponible. Los Smart Pointers (IMO) son esenciales, pero no una característica estándar del lenguaje. –

2

Puede usar C++ con .NET de dos maneras: gestionada o no. En modo administrado, la recolección de elementos no utilizados de .NET se ocupará de liberar memoria en su nombre; en modo no administrado, estás cerca del comportamiento normal/estándar de C++, por lo que debes encargarte de tu memoria.

+3

Independientemente del "modo", cada 'nuevo' es una memoria no administrada y tiene que ser desasignada manualmente por' eliminar'. C++/CLI agrega 'gcnew', pero esto no es C++ como tal, sino más bien una extensión de idioma. –

+2

Realmente estamos hablando de dos idiomas diferentes. C++ y C++/CLI –

2

Sí, tiene razón, en C++ estándar (en C++ administrado u otras variantes depende) debe utilizar eliminar después de cada nuevo. En C#, Java y otros lenguajes recogidos de basura, esto no es necesario (de hecho, la mayoría de ellos no tiene un equivalente al operador "eliminar").

1

recogida automática de basura es útil, pero todavía se puede conseguir pérdidas de memoria, como muestra esta pregunta:

Memory Leaks in C# WPF

Se disminuyó en .NET y Java, pero eso no quiere decir que permite mala codificación para ser atendido automáticamente.

Por lo tanto, en C++ debe liberar explícitamente lo que solicita, y creo que a veces es mejor, ya que está al tanto de lo que está sucediendo. Desearía en .NET y Java que el recolector de basura hiciera poco en el modo de depuración, para ayudar a asegurar que las personas estén al tanto de lo que están haciendo.

8

Su afirmación sobre el operador new es totalmente correcta ... pero simplifica un poco la semántica de C++.

En C++, los objetos se pueden crear en la pila o en el montón:

class Foo {}; 

int main() { 
    Foo obj1; 
    Foo* obj2 = new Foo(); 
    delete obj2; 
} 

En el ejemplo anterior, obj1 se crea en la pila y obj2 se crea en el montón (con nuevo). Los objetos creados en el montón no se destruyen hasta que se llama explícitamente a eliminar. Sin embargo, los objetos en la pila se destruyen automáticamente cuando salen del alcance (es decir, cuando main() retorna en este ejemplo).

Esto habilita la expresión "Adquisición de recursos es inicialización" (a.k.a. RAII) en C++, que es mucho más poderosa que la recolección de basura básica. Los recursos que se deben limpiar (memoria de pila, sockets, archivos, conexiones de base de datos, etc.) generalmente se colocan en objetos basados ​​en pila cuyos destructores se encargan de la limpieza.

Por el contrario, Java y C# no permiten que se construyan objetos en la pila, y no garantizan que la recopilación ocurra ni que se ejecuten los finalizadores (no soy un tipo C#, entonces puedo ser un poco mal allí). Por lo tanto, mientras obtiene administración gratuita de la memoria de pila en Java/C#, en realidad terminará con muchos más códigos de limpieza de recursos en esos idiomas que en C++.

8

En idiomatic alto nivel C++, nunca llama eliminar.

C++ no tiene un recolector de basura estándar que funcione igual que en C#, y por lo tanto es cierto que fundamentalmente, new y delete deben emparejarse. Sin embargo, hay mecanismos en C++ que eliminan completamente el explícito uso de delete para el código escrito en el estilo moderno.

La primera cosa a destacar es que en C++ utiliza newcon mucha menos frecuencia de las que usa new en C#. Esto se debe a que en C# se usa new cada vez que se crea una instancia de una estructura, clase o matriz, pero en C++, se usa new solo cuando se desea administrar un elemento de datos dinámicamente. La mayoría de los datos en C++ no requieren una gestión dinámica y, por lo tanto, pueden crearse sin el uso de new. [Dicho de otra manera, new tiene un significado diferente en C# que en C++. En C++ se indica específicamente la asignación dinámica, mientras que en C# se utiliza para cualquier tipo de construcción.]

En segundo lugar, cada vez que llaman new en C++, el valor de retorno debe ser entregado directamente a un smart pointer. El puntero inteligente se asegurará de que se llame automáticamente al delete en el momento apropiado.

Por cierto, a menos que sea un gurú escribiendo una biblioteca de bajo nivel (o un estudiante que esté aprendiendo cómo hacer esto), nunca debe llamar al new para asignar una matriz en C++. La biblioteca estándar (y también Boost/TR1) proporciona clases de plantillas que asignan y administran las matrices por usted.

En resumen, C++ No usa un recolector de basura pero tiene su propia forma de gestión de memoria automática . Existen diferencias sutiles entre los dos enfoques, pero ambos enfoques automatizan la liberación de memoria, eliminando así la mayoría de los tipos de pérdidas de memoria.

La manifestación autorizada de estos conceptos se da por C++ creador Bjarne Stroustrup en respuesta a la pregunta: How do I deal with memory leaks?

Ver también:

+0

De la misma manera, si usa delete, probablemente sea un error. El problema es que el uso de eliminar asume que usted sabe exactamente cómo procederá el flujo de control del programa para que la eliminación se produzca en el momento apropiado. Esta es una suposición fácil, pero ingenua, de hacer. En primer lugar, requiere cierta medida de cuidado para posicionar correctamente la operación de eliminación. Más importante aún, las excepciones generalmente pueden ocurrir en cualquier punto intermedio del código y violar sus suposiciones sobre el flujo de control. Reparar esto con try/catch es posible, pero no es una "mejor práctica". – nobar

+1

La demostración de Bjarne es un poco anticuada, particularmente su uso de auto_ptr <> que generalmente se rechaza hoy en día (hay mejores alternativas). Pero esto demuestra la madurez de lo que antes llamaba "el estilo moderno". Bjarne ha estado enseñando este enfoque durante mucho tiempo. – nobar

+0

Aquí hay una publicación que dice lo mismo pero explica más sobre las mecánicas, incluida la discusión de algunas de las características más nuevas de la biblioteca: http://stackoverflow.com/questions/4963610/visual-c-native-memory-management- mejores prácticas/4963633 # 4963633 – nobar

Cuestiones relacionadas