Posso eliminare un puntatore che punta in una matrice allocata, ma non all’inizio?

Mi sto chiedendo in particolare riguardo alla seguente situazione (che ho scoperto in qualche codice con cui devo lavorare):

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

Questo codice sembra funzionare bene – cioè non si blocca (win32, costruito con VS2005).

Questo è “legale”? Certamente non sembra giusto.

No, non è definito passare alcun indirizzo da delete che non è stato restituito da new .
Ecco la citazione dallo standard.

§ 3.7.4.2-3

Se una funzione di deallocazione termina lanciando un’eccezione, il comportamento non è definito. Il valore del primo argomento fornito a una funzione deallocazione può essere un valore puntatore nullo; in tal caso, e se la funzione deallocazione è fornita nella libreria standard, la chiamata non ha alcun effetto. Altrimenti, il valore fornito all’operatore delete(void*) nella libreria standard deve essere uno dei valori restituiti da una precedente chiamata di uno dei due operatori new(std::size_t) o operator new(std::size_t, const std::nothrow_-t&) nella libreria standard e il valore fornito all’operatore delete[](void*) nella libreria standard deve essere uno dei valori restituiti da una precedente chiamata di uno dei due operator new[](std::size_t) o operator new[](std::size_t, const std::nothrow_t&) nella libreria standard.

No, non legale. Puoi delete solo ciò che torni da new , e lo stesso vale per il new[] e delete[]

No non lo è. È necessario chiamare delete [] sullo stesso indirizzo (o puntatore) ricevuto da new []. Potresti solo essere fortunato che non si blocchi, ma sicuramente non cancella la memoria in modo appropriato.

Riferimenti :

Da 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). 

Da 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. 

Da documenti standard ,. 5.3.5.2 Delete ,

… Nella seconda alternativa (cancella array), il valore dell’operando di delete deve essere il valore del puntatore risultante da un array precedente new-expression.72 In caso contrario, il comportamento non è definito. ….

Anche la nota sub 72) afferma che,

72) Per gli array di lunghezza diversa da zero, equivale a un puntatore al primo elemento dell’array creato da tale nuova espressione. Gli array a lunghezza zero non hanno un primo elemento.

E quindi sì, non è definito.

Lo standard afferma che è ansible eliminare solo ciò che è stato assegnato con nuovo, ma ciò non spiega perché si blocca o, in questo caso, non si blocca.

Quando elimini un puntatore, lo stai rimettendo nell’heap per essere riutilizzato nelle allocazioni future. L’implementazione tipica fornisce un puntatore, con un int appena prima che il puntatore tracci la memoria nel blocco (è la tipica implementazione di malloc). In questo modo, per un tipico sistema a 32 bit.

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

Quindi, se punti nel mezzo del blocco, interpreterà i byte prima di esso come una dimensione, con risultati potenzialmente disastrosi. Sei stato salvato dal vedere l’incidente con il tuo piccolo esempio di codice. Probabilmente, non hai mai provato ad allocare dopo quel punto. Se provi ad assegnare qualcosa dopo, probabilmente si bloccherà, perché proverà a riciclare parte della memoria che hai appena restituito.

La ragione esatta dipende ovviamente dall’implementazione. Questo è solo per spiegare un modo comune in cui le eliminazioni impropri possono fallire, non specificamente verificate per Visual Studio 2005.

Non è legale Il fatto che non si blocchi non significa che non lo farà in altre circostanze. Sicuramente andrà in crash se abiliti il ​​verificatore. E in ogni caso non libererà il tuo array. Questo è solo il CRT / Windows che consente al tuo programma di non bloccarsi quando dovrebbe

inserisci la descrizione dell'immagine qui

Se non si passa l’inizio di esso, l’ delete non otterrà le informazioni extra.