2010-12-04 19 views
10

Tengo un objeto con un vector de punteros a otros objetos en ella, algo como esto:¿Es posible eliminar un objeto no nuevo?

class Object { 
    ... 
    vector<Object*> objlist; 
    ... 
}; 

A continuación, se añade objetos a la lista en estas dos maneras:

Object obj; 
obj.objlist.push_back(new Object); 

y

Object name; 
Object* anon = &name; 
obj.objlist.push_back(anon); 

Si un hacer un destructor que es simplemente

~Object { 
    for (int i = 0; i < objlist.size(); i++) { 
     delete objlist[i]; 
     objlist[i] = NULL; 
    } 
} 

¿Habrá consecuencias adversas en términos de cuándo intenta eliminar un objeto que no se creó con nuevo?

+0

Sé que podría ser mejor con un iterador, pero 'objlist' era originalmente y array y no he tenido tiempo para cambiar el ciclo. –

Respuesta

28

Sí, habrá efectos adversos.

No debe delete un objeto que no fue asignado con new. Si el objeto fue asignado a la pila, su compilador ya generó una llamada a su destructor al final de su alcance. Esto significa que llamarás al destructor dos veces, con efectos potencialmente muy malos.

Además de llamar al destructor dos veces, también intentará desasignar un bloque de memoria que fue nunca asignado asignado. El operador new supuestamente coloca los objetos en el montón; delete espera encontrar el objeto en la misma región que los pone el operador new. Sin embargo, su objeto que no estaba asignado con new vive en la pila. Esto probablemente bloqueará tu programa (si no se cuelga después de llamar al destructor por segunda vez).

También se meterá en graves problemas si su Object en el montón vive más tiempo que su Object en la pila: obtendrá una referencia oscilante en algún lugar de la pila, y obtendrá resultados incorrectos/bloquee el la próxima vez que accedas a él.

La regla general que veo es que las cosas que viven en la pila pueden hacer referencia a cosas que viven en el montón, pero las cosas en el montón no deberían hacer referencia a la pila debido a las altas posibilidades de que sobrevivan a la pila objetos. Y los indicadores para ambos no deberían mezclarse.

+0

Ya veo. ¿Hay alguna manera de garantizar que cuando se destruye el objeto, se elimine todo en objlist que se puso allí con nuevo, y nada más? –

+1

@ Keand64 No hay función de idioma que lo ayude allí. Una vez que tienes un puntero, no puedes (sin operaciones de magia oscura/operaciones inseguras dependientes de la plataforma) saber si apunta a algún lugar en la pila o en el montón. En general, es una mala idea mezclar objetos que viven en la pila y objetos que viven en el montón. Su mejor opción sería usar 'new' para todos ellos. – zneak

+0

@ Keand64: Lo que se supone que debes hacer es hacer que el mismo código sea responsable del 'nuevo' que del' borrar'. Para los contenedores, permite que el contenedor haga ambas cosas, haciendo que copie explícitamente todo lo que se coloca en el contenedor. (Esto también lo protege contra el código de llamada, lo que permite que lo señalado caiga fuera del alcance). Pero ** no escriba sus propios contenedores de todos modos **; la biblioteca estándar proporciona lo que necesita. –

1

Esto no funcionará - si delete un objeto que no fue asignado por new ha violado las reglas o el operador delete.

Si necesita tener sus objetos vectoriales almacenados que pueden o no necesitar ser eliminados, necesitará hacer un seguimiento de eso de alguna manera. Una opción es usar un puntero inteligente que realice un seguimiento de si el objeto apuntado es dinámico o no. Por ejemplo, shared_ptr<> le permite especificar un objeto deallocator al construir la shard_ptr<> y como los documentos mencionan:

Por ejemplo, un "no-op" deallocator es útil cuando se devuelva un shared_ptr a un objeto de forma estática asignada

Sin embargo, debe tener cuidado al pasar punteros a las variables automáticas; si la vida del vector es más larga que la vida útil de la variable, en algún momento se referirá a la basura.

3

No, sólo se puede delete lo que new ed

Object* anon = &name; 

Cuando el nombre se sale del ámbito, tendrá un puntero no válido en su vector.

1

Lo que en realidad está preguntando es si es seguro eliminar un objeto no asignado a través del new a través del operador delete, y si es así, ¿por qué?

Desafortunadamente, esto está ofuscado por algunos otros problemas en su código. Como se mencionó, cuando nombre sale del alcance, terminará con un puntero no válido.

Consulte zneak's answer para saber por qué su pregunta original no da como resultado una operación segura, y por qué el alcance para nombre realmente importa.

Cuestiones relacionadas