2010-11-24 13 views
13

¿El siguiente código C++ es una pérdida de memoria?C++: ¿push_back (new Object()) es una pérdida de memoria?

list.push_back(new String("hi")); 

Según tengo entendido, push_back desde cualquier std collection/container siempre hace una copia. Entonces, si se copia la nueva cadena, nada puede borrar la cadena nueva, ¿verdad? ya que no hay referencia después del push_back ...

¿Estoy correcto o incorrecto aquí?

Gracias.

JBU

edición: creo que estoy equivocado, ya que los nuevos devolverá un puntero ... siempre nos quedará el puntero para ser capaz de eliminar la nueva cadena

+1

Depende de la definición de 'list'. –

+3

Depende de qué 'lista' es. Suponiendo que es una 'std :: list ', @UncleBens es correcta: aún así es posible limpiarla correctamente la mayor parte del tiempo. Pero debes hacer esa limpieza manualmente; 'std :: list' no lo hará por usted. – aschepler

+0

Sí. Porque la variable 'lista' es en realidad de un tipo que tiene una función llamada 'push_back' con un cuerpo vacío. –

Respuesta

6

No, los negocios de vectores punteros y la copia está hecha del puntero. Puede eliminar el objeto en cualquier momento posterior.

(Usted puede obtener una fuga, si la instrucción pasa a lanzar una excepción y no capturar y manejar adecuadamente. Es por eso que usted podría considerar el uso de punteros inteligentes.)

+3

"si la declaración arroja una excepción y no la detecta y maneja correctamente" - en el caso de esta declaración, no hay manera de manejarla correctamente, realmente. Si 'push_back' arroja, entonces no ha almacenado el puntero, y no hay forma de liberarlo porque este código de llamada tampoco tiene el puntero. Supongo que en teoría podría hacer algo con 'String :: operator new', pero eso no parece divertido. –

1

Estás en lo correcto, siempre y nada borra la cadena cuando se elimina de la lista.

1

Sí, esto es una pérdida de memoria dado que de alguna manera se toman medidas para eliminar los punteros contenidos.

Y la mejor manera de lograr eso es usar un puntero inteligente. Por ejemplo, shared_ptr de Boost o shared_ptr de C++ 0x.

+0

scaled_ptr ?? ¿Te refieres a shared_ptr? –

+0

@Fred: uh. tal vez ... –

+0

La única otra cosa que podría pensar que quería decir es scoped_ptr, pero eso no funcionará en un contenedor ya que no se puede copiar. –

4

Si veo este código, sospecho que es posible una pérdida de memoria. En la superficie, parece estar agregando un String* asignado en un list<String*>. En mi experiencia, esto a menudo va seguido de un mal código de manejo de errores que no libera adecuadamente la memoria asignada.

Si bien esto es peligroso en muchas circunstancias, no es necesariamente una pérdida de memoria. Consideremos el siguiente ejemplo:

class Container { 
    ~Container() { 
    std::list<String*>::iterator it = list.begin(); 
    while (it != list.end()) { 
     delete *it; 
     it++; 
    } 
    } 

    void SomeMethod() { 
    ... 
    list.push_back(new String("hi")); 
    } 

    std::list<String*> list; 
} 

En este código no hay fugas debido a la clase que contiene es responsable de la memoria asignada y liberará en el destructor.

EDITAR

Como aschepler señaló que todavía hay una fuga si el método push_back lanza una excepción.

+3

Si la llamada a 'push_back' arroja una excepción, esto sigue siendo una pérdida. – aschepler

+1

También existe el riesgo de eliminación doble a menos que declare un constructor de copia y operador de asignación de copia. –

0

Puede eliminar el objeto haciendo:

delete list[i]; 
list.erase(list.begin() + i); 

o borrar toda la lista por:

for (unsigned int i = 0; i < list.size(); ++i) 
{ 
    delete list[i]; 
} 
list.clear(); 
0
list.push_back(new String("hi")); 

¿Por qué estás asignando cadenas dinámicas en primer lugar?A menos que usted desea comunicarse entre diferentes partes de su programa cambiando cuerdas (que sería bastante inusual), deshacerse del puntero:

std::list<std::string> list;   // note: no pointer! 
list.push_back(std::string("hi")); // explicitly create temporary 
list.push_back("hi");    // alternative: rely on coercion 
8

Sí, pero no por la razón que piensa.

Dependiendo de cómo se defina e inicialice list, push_back podría arrojar una excepción. Si lo hace, el puntero devuelto desde new se pierde y nunca puede liberarse.

Pero suponiendo push_back regresa con éxito, se almacena una copia del puntero devuelto por new, por lo que puede liberar la memoria más adelante llamando delete en esa copia, por lo que no hay memoria se pierde todo el tiempo que hace llamada delete correctamente.

+0

¡Guau, la única respuesta correcta de las siete! – Mankarse

+0

Lo siento pero no pude averiguar si el puntero solo se copió o si los datos apuntados también se copiaron. Por ejemplo: - String * str = new String ("HI"); list.push_back (str); Ahora puedo llamar delete str y aún poder acceder a "HI" de la lista porque valgrind muestra una fuga en list.push_back sin ninguna llamada de eliminación. –