2009-06-14 12 views
15

He aprendido dolorosamente durante los últimos días mucho sobre la programación en C++.
Me encanta :)
Sé que debería liberar memoria: las reglas doradas "each malloc = free" o "each new = delete" existen ahora en mi mundo, pero las estoy usando para objetos bastante simples.
¿Qué pasa con el vector? Siempre que puedo, uso vector.clear() pero eso claramente no es suficiente, porque tengo grandes pérdidas de memoria.
¿Podría orientarme sobre cómo debo tratar esta cosa?¿Debo eliminar el vector <string>?

* Editar
Gracias, sus comentarios me hicieron pensar en el algoritmo de esta aplicación y voy a poder eliminar el vector totalmente. : O
Lo siento, comencé a explicar cuál es mi caso de uso aquí y descubrí lo que realmente necesito. Es así cuando codifica los últimos 3 días durante 18 horas al día: | * Editar 2
Esto es una locura. Mediante pequeños cambios en el código, eliminé el uso de memoria de 2x130 mb (en constante crecimiento) a 2x 13,5mb, tamaño constante. Gracias por hacerme pensar sobre eso de otra manera.

Btw. tal revisión de código propio tiene un nombre - ¿alguien recuerda eso? Es cuando le preguntas a alguien (incluso a tu madre o tu perro) y comienzas a explicar cuál es tu problema, y ​​de repente tú mismo resuelves este problema de 5 horas, simplemente tratando de verlo desde otro punto de vista, o simplemente tratando de resumir qué es todo sobre. A menudo me encuentro atrapado en eso ...

+5

Como es nuevo en la gestión de la memoria, quizás pueda explicar cómo sabe que está perdiendo memoria. Algunas formas de medir las pérdidas de memoria no reflejan realmente lo que está sucediendo. –

+0

Es posible que desee publicar un código de ejemplo de cómo está utilizando la clase vectorial. Por ejemplo, ¿tiene vectores de punteros para objetos creados dinámicamente? –

+0

bueno, simplemente veo que la ejecución de mi aplicación resulta en más y más memoria ocupada. Estoy ejecutando operaciones bastante fáciles (haciendo hashes md5 en 2 procesos, vinculados con mpcih2), para mi prueba son exactamente 25 millones de operaciones. Un proceso envía a los otros paquetes de datos (cadenas) y el segundo calcula hashes para eso. Al final de la ejecución tengo 2x 130 mb tomados. Eso es demasiado para ser normal. – IamDeveloper

Respuesta

19

La regla es que cuando eliminas un vector de objetos, se llamará al destructor de cada elemento. Por otro lado, si tiene un vector de punteros, vector::clear() no llamará al delete y deberá eliminarlos usted mismo.

Así que si todo lo que tiene es un vector de cadenas y no apunta a cadenas, entonces las pérdidas de memoria deben ser causadas por otra cosa.

+0

¿Eso aplica en general? Si tengo una clase que tiene 'std: vector' como una de sus propiedades, ¿C++ llamará a ese destructor cuando se destruya la clase? –

+4

Sí. Cuando se destruye un objeto, se llama al destructor de todos sus miembros de datos. Pero como dije, tenga en cuenta lo que está almacenando en el vector. Si es un vector de objetos, los objetos se destruirán junto con el vector. Si es un vector de punteros, entonces debe eliminarlos usted mismo. – Dima

7

Llamar a v.clear() destruirá todos los objetos que se encuentran actualmente dentro de v, pero no liberará la memoria (se supone que el vector pronto se llenará de nuevo).

Si realmente desea liberar la memoria, el lenguaje es

vector<string>().swap(v); 

Esto creará un nuevo vector (temporal) y cambiar su contenido con v. El vector temporal se destruye, liberando la memoria junto con él.

+0

Ahora veo la intención detrás de eso, pero me parece bastante incómodo. ¿Y sería lo mismo que v.swap (vector ())? – ypnos

+2

Puede parecer incómodo, pero es la forma idiomática de disminuir 'v.capacity()'. Su fragmento no se compilará, ya que 'vector ()' es un valor r y no puede vincularse a una referencia no constante. – avakar

+0

Para aclarar: en a.swap (b), a y b no son iguales. El intercambio de miembros tiene un argumento, una referencia no constante. Puede llamar a las funciones de miembros temporales no const, por lo que en a.swap (b), a puede ser temporal. Pero b está vinculado a una referencia no constante y no puede ser temporal. – MSalters

4

El vector (como todos los contenedores estándar) es propietaria de los objetos dentro de ella.
Así que es responsable de destruirlos.

Nota: Si su vector contiene punteros, entonces posee los punteros (no es lo que apuntan los punteros). Entonces estos deben ser eliminados. Pero hay formas más fáciles.

Puede utilizar un vector de punteros inteligentes. De hecho, deberías estar usando algún tipo de puntero inteligente para casi todo.Si está utilizando punteros, es probable que todavía esté programando como un programador en C.

Así:

std::vector<int> data; // clear is fine. 

std::vector<int*> data1; // Now things need to be deleted. 
// alternative 1: 
std::vector<boost::shared_ptr<int> > data2; // The shared pointer will auto 
              // delete the pointer. 
// alternative 2: 
boost::ptr_vector<int> data3;    // Here the container knows that 
              // it is holding pointers and will 
              // auto de-reference them when you 
              // its members. 

Pero parece que usted necesita para empezar a pensar en aprender acerca de punteros inteligentes.

int* x = new int(5); 
// Do stuff. 
*x = 8; 
delete x; 

// --- Instead use a smart pointer: 
std::auto_ptr<int> x(new int(5)); 
// Do stuff. 
*x = 8; 
// No delete (the auto ptr handles it. 
5

Eliminar elementos de los contenedores STL garantiza la invocación de destructores en estos elementos. Sin embargo, si tiene un contenedor de tipo pointer-to-T, debe liberar la memoria apuntada usted mismo (en este caso, se llama al "destructor" del puntero, que es una operación no operativa).

Si no desea administrar la memoria manualmente en este caso, considere usar un smart-pointer solution o un pointer container.

7

No necesita hacer esto. std :: string se limpia solo, por lo que las cuerdas no son su problema. Recuerde que USTED no usó new para no tener que usar delete.

Probablemente deberías aprender sobre RAII - hace la asignación y la desasignación mucho más simples. Evitarás pérdidas de memoria de esta manera.

1

Si tiene un vector y se sale del alcance, se destruirán todos los objetos del vector. No es realmente necesario llamar a clear() a menos que desee volcar el contenido y reutilizar el vector.

Sin embargo, si por casualidad está utilizando algo así como un vector, entonces no se invocará el destructor de los objetos a los que se apunta, ya que el vector destructor no sigue las direcciones indirectas representadas por los punteros.

Dicho todo esto, ¿realmente ha confirmado que tiene pérdidas de memoria genuinas y que son causadas por los datos en el vector?

0

Como se sugirió rlbond, use RAII.

Es una buena regla general nunca poner nuevas y eliminar llamadas en el flujo de código principal. Siempre trate de ponerlos en objetos para que el destructor de objetos libere lo que necesita ser liberado. De esta forma, evita tener que recordar llamar a eliminar y hace que la excepción de su código sea segura (suponiendo que hace que la excepción de las operaciones de su objeto sea segura).

Por ejemplo, si tiene un vector de punteros a cadenas STL o arrays de caracteres C, colóquelo en un StringContainer (use un nombre mejor) y haga que StringContainer contenga un vector y en el destructor StringContainer ejecute un bucle para eliminar cada cadena en el vector.

Puede hacer que el vector dentro de StringContainer sea un miembro público y perder el tiempo directamente, pero es aún mejor diseñarlo de forma privada o protegida y agregar algunas funciones de miembros para administrar el vector de cadena *.

Por lo que su programa principal de C++ nunca debería ver una nueva o eliminar en cualquier lugar. En su lugar, debe tener una gran cantidad de objetos asignados de pila, auto_ptrs y shared_ptrs.

Cuestiones relacionadas