Newsgroup: it.comp.lang.c++
Titolo: delete [] and const_cast<>: anomalie o ignoranza?

Salve a tutti, questo è il mio primo post su questo NG...
Vengo subito al sodo.
Sto sviluppando un modulo ISAPI per IIS con VC++ 6.
ho una funzione che fa questo, grossolanamente:
f(...)
{
  char * bfQueryString ;
    ...
bfQueryString =  new char [strlen(pRB->pECB->lpszQueryString) + 1];
...
delete [] bfQueryString;
}
secondo il mio modestissimo parere è un banalissimo costrutto... eppure,
ecco cosa succede...
Sotto alcune circostanze (in cui essenzialmente, a differenza degli altri
casi, faccio delle allocazioni dinamiche prima di entrare nella funzione in
questione) mi capita di beccarmi una bella exception sulla delete finale...
controllo il valore del puntatore dopo l'allocazione e prima della
deallocazione ed essi coincidono???
Allora non mi fido del tracer, e cosa faccio?... definisco come * const la
bfQueryString e uso il const_cast... ovvero, la f() diviene:
f(...)
{
  char *  const bfQueryString  = NULL;
    ...
const_cast<char *>(bfQueryString) =  new char
[strlen(pRB->pECB->lpszQueryString) + 1];
...
delete [] bfQueryString;
}
ecco, ora tutto va bene!!!
Qualcuno sa spiegarmi chiaramente che cosa cambia, in termini di
allocazione/deallocazione o quant'altro concerne lo straccio sottopostovi,
tra i due casi?
Ve ne sarei davvero molto grato.
Vi prego di rispondermi anche in privato: mailto:
jan...@libero.it
Grazie in anticipo
PS.: Se dovesse risultarvi anomala la cosa, come risulta a me, me lo
comunicate?

tra i due casi?
Quando un programma C o C++ si blocca in una delete[] o in una new[]
non significa necessariamente che *quella* delete o *quella* new
siano errate. Spesso quello che stai verificando sulla tua pelle
e' una delle conseguenze di quello che tecnicamente viene definito
dallo standard C++ come "undefined behaviour".
Immagina ad esempio di scrivere qualcosa come:
   char *b = new char[100]; // Alloca
   delete[] b;              // Dealloca
   b[0]=1;                  // Scrive dopo aver deallocato!!
In C++ la terza istruzione non e' permessa ma le regole dicono
solo che se fai qualcosa del genere il programma e' libero di
fare quello che meglio crede; ad esempio:
  - Bloccarsi segnalandoti un crash su quella istruzione
  - Funzionando tranquillamente come se non fosse successo nulla
  - Funzionando *apparentemente* ma creando un crash 2 milioni
    di istruzioni eseguite dopo
  - Funzionando solo in debug mode (ovvero crashando solo in release
    quando non puoi usare il debugger)
  - Funzionando *apparentemente* ma salvando i file dell'utente
    in modo errato
  - Formattandoti il disco fisso e mandando una mail di insulti
    a tua suocera o al tuo capo.
Purtroppo la prima eventualita' e' l'eccezione e non la regola...
molto ma molto piu' frequenti sono la seconda e la terza.
In particolare quando avvengono degli "sconfinamenti", ovvero
delle scritture su aree dati non allocate, spesso la "vittima"
del problema che provochera' il crash sara' una new o una delete.
Questo e' dovuto al fatto che se scrivi a caso in memoria hai
una buona probabilita' di danneggiare la struttura globale dello
free-store e chi si accorgera' (urlando) del problema saranno
le routine di allocazione/deallocazione memoria che questa
struttura la attraversano/aggiornano.
I motivi per cui il C++ non richiede che si generi un errore
quando si sconfina sono principalmente dovuti alle prestazioni.
Nonostante il C++ permetta di costruire della astrazioni di un
certo livello infatti si tratta comunque di un linguaggi molto
vicino al "metallo" e la sua filosofia di base presuppone che
il programmatore non faccia mai errori di questo tipo.
A cosa si riduce tutto questo gran parlare ? Semplice:
il problema devi cercarlo in quello che avviene *prima*
di quel punto. Quando fai questa ricerca devi resistere
a due pericolosissime tentazioni:
 1) Fermarti quando il problema smette di presentarsi
    ma non hai capito perche':
    I bug non sono cose che appaiono e scompaiono da
    sole... sono errori logici del programma e come
    tali resteranno sino a che non li trovi ed elimini.
    "squassare" il codice facendo qualche cambiamento
    qua e la' sino a che il problema scompare (o per
    meglio dire sembra scomparire) non e' una tecnica
    intelligente: il bug semplicemente si sara' nascosto
    piu' profondamente e ti mordera' dolorosamente il
    giorno della presentazione della tua applicazione
    facendoti fare la figura del mandarino.
    Quindi, mentre vai a caccia, e' importante non fare
    nessuna modifica che non abbia un senso logico in
    relazione al crash. Se vedi altri errori allora
    segnati la modifica ma falla in un altro momento:
    stai dando la caccia a un nemico ben preciso e meno
    "rumore" fai meglio e'.
    E' anche importante capire che gli errori logici
    sono il nemico e il crash e' invece un amico. Tu
    non devi cercare di eliminare i crash, devi cercare
    di eliminare gli errori logici che ti sono segnalati
    dai tuoi amici crash. Per fare questo e' consigliabile
    infarcire i programmi di un sacco di crash di controllo
    (la macro assert() implementa una forma di crash
    pilotato... dovrebbe essere usata molto piu' di
    quanto non viene fatto normalmente; nota anche che
    il "crash" di windows altro non e' che una assert()
    fatta a livello di sistema operativo o di libreria).
 2) Pensare che sia un bug del compilatore e girare
    attorno alla cosa con un trucco.
    E' il tuo programma a essere sbagliato, non il
    compilatore. Questa frase e' brutale ma risponde nel
    99.9999% dei casi al vero. Se proprio sei disposto
    a scommettere la casa e il tuo primogenito sul fatto
    che il tuo codice e' privo di errori allora vai
    comunque a fondo della cosa e trova esattamente
    *dove* il compilatore o la libreria sbagliano.
    Il pensiero che il compilatore sia in errore deve
    essere l'*ultimo* che ti viene in mente... e comunque
    non giustifica (il solo sospetto) l'interruzione
    delle ricerche sui tuoi errori.
    Nota che i compilatori ovviamente non sono perfetti...
    pero' incolpare gli strumenti (senza provare
    inequivocabilmente il difetto) non avvicina per nulla
    la soluzione del problema e tende a costituire una
    sorta di mentalita' di "programmazione per tentativi"
    che e' molto dannosa in genere, e un autentico
    suicidio in un ambito complesso e tagliente come C/C++.
Spero tu non ti offenda per queste considerazioni che,
come ho detto nella nota iniziale, non sono rivolte a
te in particolare ma a tutti (me incluso).
Buona caccia...
HTH
Andrea

[
    I NG servono anche a farsi compagnia e a condividere le frustrazioni che
un C/C++ coder conosce sempre... ma quando senti il rumore sottile del vento
alzato dal tuo codice che gira... allora ti rendi conto che ne è valsa la
pena!
]
Grazie a quanti hanno preso in cosiderazione la mia richiesta precipitosa
d'aiuto.
Il problema risiedeva 1047 linee prima ed è stato fixato subito dopo il
post...
Come spesso accade: dopo lo sfogo la riflessione!!!
Grazie Andrea per la tua bellissima visione del coding, da vero
CodeWarrior!!!
:^)
Alla prossima, _SERIA_ :^) questione...

     fatta a livello di sistema operativo o di libreria).
secondo me allora i sorgenti di windows sono pieni zeppi di assert :-)))
E pensa cosa succederebbe se ce ne mettono ancora di piu`! ;-)
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.73, higher than 99% of all previous test takers.
C Language: 3.79, higher than 92% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 ha scritto
nel messaggio news:a57tsb$vev$2...@newsreader.mailgate.org...


 le supposizioni "asserite" siano corrette.
la mia era, evidentemente, una battuta.
