Posso nuovo [], poi il cast del puntatore, quindi eliminare [] in modo sicuro con tipi built-in in C ++?

StackOverflow https://stackoverflow.com/questions/2140319

Domanda

Nel mio codice che ho in modo efficace il seguente:

wchar_t* buffer = new wchar_t[size];
// bonus irrelevant code here
delete[] reinterpret_cast<char*>( buffer );

Tipi in questione sono tutti incorporato e quindi hanno distruttori banali. In VC ++ il codice precedente funziona allright - new[] solo alloca la memoria, quindi delete[] solo lo libera

.

E 'accettabile in C ++? E 'un comportamento indefinito?

È stato utile?

Soluzione

Il mio primo pensiero è stato che si tratta di un comportamento indefinito.

  

5.3.5 / 3: "Nella seconda alternativa ( Elimina array ) se la dinamica   tipo di oggetto da eliminare   differisce dal suo tipo statico, la   comportamento è indefinito. 73) .

La nota 73 si legge: "Questo implica che un oggetto non può essere cancellata con un puntatore di tipo void* perché non ci sono oggetti di tipo void".

Probabilmente l'oggetto nel tuo esempio non lo fa sono un tipo dinamico, dal momento che la definizione di "tipo dinamico" alla 1.3.3 parla di "oggetto più derivata", e la definizione di "più derivati oggetto" a 1,8 / 4 sta parlando di oggetti di tipo classe. Così ho continuato a guardare:

  

5.2.10 / 3: "[reinterpret_cast] potrebbe, o non potrebbe, produrre una rappresentazione   diverso dal valore originale "

     

5.3.5 / 2: "Il valore della operando di delete sarà il valore del puntatore   che ha portato da una matrice precedente    new-espressione ".

Non sono sicuro se un reinterpret_cast comporta lo stesso valore di puntatore come era entrata, oppure no. Forse è chiarito da qualche altro pezzo dello standard che non ho ancora trovato. Non direi questo codice "OK" senza trovare qualcosa di affermare definitivamente che se si reinterpret_cast un puntatore, il risultato è lo stesso "valore del puntatore" come prima, in modo che facendo passare a eliminare [] si sta passando "il valore del puntatore "dalla nuova [].

  

5.2.10 / 7: "Se non fosse che la fusione [tra alcuni tipi di puntatore] e   al suo tipo originale fornisce il   valore del puntatore originale, il risultato di   una tale conversione puntatore   non specificato".

Questo appare come una cattiva notizia per me - è vistosamente non dice che il cast produce lo stesso valore, solo che la coppia di calchi più e di nuovo, produce lo stesso valore. Questo mi fa pensare che il singolo getto è permesso di dare un valore diverso, ma è solo suggestione, non è esplicito. Questo è il solito problema con la regola che "se la norma non precisa il comportamento, quindi il comportamento è indefinito". Solo perché non afferma in uno qualsiasi dei paragrafi posso trovare utilizzando l'indice, non significa che non afferma da qualche altra parte ...

Sappiamo che in pratica si può lanciare cose da unsigned char * al fine di ispezionare i loro byte, o void * di copiare i POD usando memcpy, quindi ci deve essere qualche calchi garantiti per creare alias. Si potrebbe pensare che se l'implementazione non creare alias con alcuni calchi, allora si sta passando il "stesso valore" che hai ricevuto dal nuovo []. Ma io non sono ancora sicuro che è abbastanza buono per delete []. Penso che mi manca qualcosa di importante.

Altri suggerimenti

Si tratta di un comportamento indefinito perché delete[] invoca il distruttore sbagliata. Tuttavia, wchar_t e char sono POD, così non hanno distruttore dedicato e tutto delete[] non fa altro che chiamare l'implementazione di heap per liberare il puntatore. Pertanto, è più probabile che il lavoro, non si perde di byte. Ma in senso stretto è ancora indefinito.

Almeno come avevo letto, si dispone di un tipo statico (il tipo del puntatore) che si differenzia dal tipo dinamico (il vero tipo di oggetto che punti a). Stando così le cose, la seconda frase del §5.3.5 / 3 si applica:

  

Nella seconda alternativa (cancella array) se il tipo dinamico del   oggetto da eliminare differisce dal suo tipo statico, il comportamento è indefinito.

Modifica: Dal momento che quello che a quanto pare vuole è quella di allocare un buffer di memoria "grezza", invece di un array di oggetti, vorrei consigliare utilizzando ::operator new invece di new[]. In questo caso, quello che stai facendo è chiaramente definita, e dà anche al lettore una chiara indicazione di intenti.

sezione ISO14882 5.2.10.3:

The mapping performed by reinterpret_cast is is implementation defined

sezione ISO14882 5.3.5.2:

The value of the operand of delete[] shall be the pointer value which resulted from a previous array new-expression

In altre parole, si tratta di implementazione definito se il delete [] invoca un comportamento indefinito. Steer chiaro.

Poiché wchar_t e char è assegnato il tipo da incasso, la funzione deallocazione corretta (void operator delete(void* ptr)) sarebbe chiamato, e non c'è distruttore per chiamare.

Tuttavia lo standard C ++ 03 dice che il risultato di reinterpret_cast<T1*>(T2*) è indefinito (sezione 5.2.10.7):

  

Un puntatore a un oggetto può essere esplicitamente convertito in un puntatore a un oggetto di tipo diverso. Salvo che   convertire una rvalue di tipo “puntatore a T1” al tipo “puntatore a T2” (dove T1 e T2 sono tipi di oggetti   e dove i requisiti di allineamento di T2 sono più severe di quelle di T1) e ritorno al suo tipo originale   produce il valore del puntatore originale, il risultato di una tale conversione puntatore è specificato.

Da un POV pratico Non riesco a immaginare un'implementazione in cui un valore wchar_t* non è un valore char* valida, in modo che il codice dovrebbe essere OK su tutte le piattaforme. Basta che non conforme agli standard ...

L'operatore delete [] utilizza internamente un ciclo di una qualche forma di distruggere gli elementi dell'array. Se gli elementi sono diversi oggetti verrà utilizzato un distruttore diversa - che può potenzialmente causare un comportamento indefinito. Dal momento che l'è un wchar e un char - tipi primitivi -. Probabilmente non causerà alcun comportamento undesireable

avviso: se si Continua a leggere lo fa a proprio rischio e pericolo PROPRIO !! DESCRIZIONE lorda di comportamento indefinito avanti. QUESTO E 'PER FINI EDUCATIVI SOLO.

Esempio 1:

Se tu avessi due oggetti che erano le stesse dimensioni e tutti i loro distruttore ha fatto è stato pari a zero il ricordo poi di nuovo sarebbe probabilmente non causare un comportamento undersireable.

Esempio 2:

Tuttavia, se tu avessi due oggetti in cui un tipo incapsulati un solo manico 4 byte a una risorsa e l'altro aveva due di questi elementi e si colato una serie di più tardi nel caso singolare - beh allora si sarebbe perdere la metà della gestisce dell'array. La situazione apparirebbe come segue:

.. 2: [1 | 2] [1 | 2] GRATIS ..

dove il '2:' rappresenta la dimensione della matrice. Dopo un avvilito il compilatore genererà una eliminazione che percepisce i dati come:

.. 2: [1] [1] LIBERA ...

quindi dopo le cose gratis apparirebbe in questo modo:

.. GRATIS [1 | 2] GRATIS ..

Perché stai usando reinterpret_cast <..>? Se si sta scrivendo qualcosa in puro C ++, quindi non è necessario reinterpretare cast. Nel tuo caso non assegnano la memoria per un oggetto. Si assegnano la memoria per wchar_t. Perché non utilizzare per stringa invece di array di wchar_t?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top