2011-06-21 15 views
17

Me pregunto específicamente sobre la siguiente situación (que descubrí en algún código que tengo que trabajar con):¿Puedo eliminar [] un puntero que apunta a una matriz asignada, pero no al inicio?

SomeClass *ar = new SomeClass[2]; 
ar++; 
delete[] ar; 

Este código parece estar funcionando bien - no es decir estrellarse (Win32, construido con VS2005) .

¿Esto es "legal"? Ciertamente no se siente bien.

+3

"parece estar funcionando bien" - sí, pero * ¿es *? : P – Marlon

+1

Esto bombardeará su programa muy bien en Vista y Win7. Es hora de deshacerse de XP. –

+5

@Marlon: ¿no es esa mi pregunta? – sje397

Respuesta

21

No, no está definido para pasar cualquier dirección a delete que no fue devuelto por new.
Aquí está la cita de la Norma.

§ 3.7.4.2-3

Si una función de cancelación de asignación termina por lanzar una excepción, el comportamiento es indefinido. El valor del primer argumento suministrado a una función de desasignación puede ser un valor de puntero nulo; si es así, y si la función de desasignación es una proporcionada en la biblioteca estándar, la llamada no tiene efecto. De lo contrario, el valor suministrado al operador delete(void*) en la biblioteca estándar será uno de los valores devueltos por una invocación previa de cualquiera de los operadores new(std::size_t) o operator new(std::size_t, const std::nothrow_-t&) en la biblioteca estándar, y el valor suministrado al operador delete[](void*) en la biblioteca estándar será uno de los valores devueltos por una invocación anterior de operator new[](std::size_t) o operator new[](std::size_t, const std::nothrow_t&) en la biblioteca estándar.

20

No, no es legal. Solo puede delete lo que obtuvo de new, y lo mismo aplica para new[] y delete[]

7

No, no lo es. Debe llamar a delete [] en la misma dirección (o puntero) que recibió de new []. Puede que tenga suerte de que no se cuelgue, pero definitivamente no borra la memoria de forma adecuada.

Referencias:

Desde http://www.cplusplus.com/doc/tutorial/dynamic/

The value passed as argument to delete must be either a pointer to a memory block 
previously allocated with new, or a null pointer (in the case of a null pointer, 
delete produces no effect). 

De http://msdn.microsoft.com/en-us/library/h6227113.aspx

Using delete on a pointer to an object not allocated with new gives 
unpredictable results. You can, however, use delete on a pointer with the 
value 0. This provision means that, when new returns 0 on failure, deleting 
the result of a failed new operation is harmless. 
0

No es legal El hecho de que no choque no significa que no vaya en otras circunstancias. Seguramente se bloqueará si activa el verificador. Y en cualquier caso, no liberará su matriz. Esto es solo el CRT/Windows que permite que su programa no falle cuando debería

6

De los documentos estándar ,. 5.3.5.2 Delete,

... En la segunda alternativa (delete tabla), el valor del operando de borrado será el valor del puntero originada como consecuencia del anterior gama de nueva expression.72) Si no, el comportamiento no está definido. ....

También el sub-nota 72) Unidos de que,

72) Para las matrices no de longitud cero, esto es lo mismo que un puntero al primer elemento de la matriz creada por esa nueva expresión Las matrices de longitud cero no tienen un primer elemento.

Y así que sí, no está definido.

1

La norma establece que solo puede eliminar lo que asignó con nuevo, pero eso no explica por qué se bloquea, o en este caso, no se bloquea.

Cuando elimina un puntero, lo está volviendo a colocar en el montón para usarlo nuevamente en futuras asignaciones. La implementación típica le da un puntero, con un int justo antes de que su puntero rastree la memoria en el bloque (esa es la implementación típica de malloc). Así, para un sistema típico de 32 bits.

 p-4 size here 
p-->  +--------+ 
     | your | 
     | block | 

Así que si apunta hacia el centro de la manzana, que va a interpretar los bytes justo antes de que como tamaño, con resultados potencialmente desastrosos. Fuiste salvado de ver el bloqueo por tu pequeño ejemplo de código. Probablemente, nunca trataste de asignar después de ese punto. Si tratas de asignar algo después de eso, probablemente se bloqueará, porque tratará de reciclar parte de la memoria que acabas de devolver.

La razón exacta obviamente depende de la implementación. Esto es sólo para explicar una forma común eliminaciones inadecuadas pueden fallar, no ha sido verificada específicamente para Visual Studio 2005.

+0

En realidad, en el código real, una matriz char se asigna para recibir mensajes de socket que son bastante frecuentes, pero el puntero al búfer se modifica a medida que se analiza el mensaje. A continuación, elimine [] s con el puntero modificado. Cosas de miedo. – sje397

0

enter image description here

Si no pasa el comienzo de la misma, la delete no va a obtener la información adicional .

Cuestiones relacionadas