2012-09-16 18 views
6

En mi clase, tengo una variable miembro std::vector<node*> children¿Es una pérdida de memoria push_back un puntero en un vector de punteros?

¿La siguiente función miembro de clase crea una pérdida de memoria?

//adds a child node 
{ 
    node* child = new node("blah","blah","blah"); 
    child->Set_Parent(this); 
    children.push_back(child); //<- Is this ok? 
} 

El vector hace una copia del puntero y tengo dos punteros a la misma memoria, y luego el original del puntero sale del ámbito, ¿verdad?

Esto puede ser simple y obvio, pero me gustaría confirmar mi suposición.
gracias

+1

Te sugiero que busques punteros inteligentes, como ['std :: shared_ptr'] (http://en.cppreference.com/w/cpp/memory/shared_ptr). –

+3

@JoachimPileborg: Incluso puede usar ['std :: unique_ptr'] (http://en.cppreference.com/w/cpp/memory/unique_ptr) en este caso, ya que' std :: vector' admite la semántica de movimiento. – bitmask

+0

Si se supone que los nodos siempre tienen padres, puedes convertirlos en una parte del constructor. Entonces solo necesitas 'children.push_back (nuevo nodo (" blah "," blah "," blah "), esto);' – dtech

Respuesta

12

No es una fuga ... todavía. Sin embargo, si el vector sale del alcance, o erase, pop_back o hace algo más que elimina elementos del vector, sin el primer elemento delete que está eliminando, tendrá una fuga en sus manos.

La forma correcta de hacer esto es cambiar de usar vector<node *> a vector<unique_ptr<node>>. Su código cambiará a

//adds a child node 
{ 
    node* child = new node("blah","blah","blah"); 
    child->Set_Parent(this); 
    children.push_back(std::unique_ptr<node>(child)); 
} 

O utilice boost::ptr_vector<node> si se puede usar Boost.

+0

Sí, podría evitar punteros crudos, ¡pero a ellos no les daría la práctica de rastrear las pérdidas de memoria! :) ¡No sabía que el impulso tenía una clase así! gracias –

+4

La última línea simplemente puede ser 'children.emplace_back (child);' –

2

Es solo una pérdida de memoria si olvida desasignar el nodo secundario cuando se llama a la clase que contiene el destructor del vector.

+1

¡genial! gracias. Sí, mi destructor recorre el vector y borra cada puntero. No encuentro ninguna razón para establecerlos como nulos ya que los indicadores también desaparecerán en breve. –

1

No es una pérdida de memoria. Todavía tiene un puntero en el vector y podrá liberar la memoria cuando sea necesario.

1

Cuando el vector sale del alcance, es destructor no destruye el objeto apuntado. Destruye el puntero, lo que no hace nada.

Su código creó ese objeto a través de new. Su código es responsable de eliminar ese objeto. Si no lo haces, tienes una filtración. Si lo hace temprano, es decir, antes de quitar el puntero del vector, tiene problemas aún mayores.

-3

Suponiendo que children es un miembro de la clase, simplemente eliminará todos los elementos del vector en el deconstructor de clase.

struct Foo{}; 

class Bar 
{ 
public: 
    Bar(){}; 
    ~Bar() 
    { 
     for(vector<Foo*>::iterator it = children.begin(); it != children.end(); ++it) 
     { 
      SAFE_DELETE((*it)); //use your own macro/template or use delete if you don't have one 
      delete (*it); 
      (*it) = NULL; 
     } 
    } 
    vector<Foo*>children; 
} 

Foo* p = new Foo(); 
children.push_back(p); 

Si ha utilizado una vector<Foo>child lugar, cada push_back en el vector crearía una copia del objeto original que se almacenará, pero ya que estamos usando punteros, en este caso asignado en el montón por ningún objeto new se crea una copia, el puntero que apunta a un objeto de término de larga vida simplemente se almacena, lo que significa que sí, tiene que eliminarlo más tarde.

+0

Eso tiene sentido.No creo que deba establecerlos como nulos, ya que todo el objeto será destruido. No entiendo el propósito de la macro/plantilla. –

+1

No entendí bien, ¿No crees que necesitas establecer un puntero a NULL cuando lo borras? 'safe_delete' ha sido una macro/plantilla conocida por edades, su propósito es eliminar de forma segura un elemento asignado de montón. Le recomiendo que lea C++ efectivo/más efectivo de David Mayhew y Scott Meyers. –

+4

No soy el que menosprecia, pero esto es una tontería. 'SAFE_DELETE' no es seguro; todo lo que hace es verificar si el puntero es nulo antes de invocar 'delete'. No hay nada de malo en eliminar un puntero nulo. No hay necesidad de esa prueba; no es necesario usar 'SAFE_DELETE' en lugar de usar' delete'. Para hacer que 'SAFE_DELETE' sea realmente seguro, de alguna manera tendría que verificar si un puntero no nulo realmente fue asignado con' new' antes de invocar 'delete'. No hace eso. Tampoco hay ninguna razón para configurar el puntero a 'NULL' después de eliminarlo; estamos en el destructor –

Cuestiones relacionadas