Newsgroup: it.comp.lang.c++
Titolo: [MFC] Puntatori ed Indirizzi


----------------------------------------


Io conosco pochissimo le MFC, ma credo che il problema sia di programmazione
C/C++ in generale.
Nel caso che non funziona, tu non allochi la memoria puntata da rect.
Mi spiego meglio.
Quando to definisci la "variabile" rect di tipo puntatore a RECT viene
riservato spazio in memoria per contenere quel puntatore (di solito un
puntatore ha dimensione pari a 4 byte. In questo caso verranno riservati in
memoria 4 byte).
Il contenuto di tale variabile (rect) sara' probabilmente pari a 0 (credo
che lo standard del C++ preveda l'inizializzazione a 0 per default delle
variabili non inizializzate. Se cosi' non fosse, allora rect avrebbe un
contenuto del tutto casuale il che non modifica minimamente la sostanza
del presente ragionamento).
Se rect e' inizializzato a 0 => rect "punta" alla zona di memoria di
indirizzo 0 (o comunque ad un indirizzo casuale).
Quando tu assegni i valori m_PosX + 20, m_PosX - 20, ecc. ai vari campi
della struttura puntata da rect, tenti in pratica di scrivere in memoria
nei dintorni dell'indirizzo 0 (o comunque ad un indirizzo casuale)
e chissa' cosa c'e' in memoria a quell'indirizzo in quel momento
(magari c'e' il vettore delle interruzioni o comunque una qualche parte del
sistema operativo che tu tenti di sovrascrivere!!).
Analogamente quando tu passi rect al metodo Ellipse in realta' passi
a tale metodo un indirizzo che e' 0 (o comunque casuale).
Nella versione che funziona invece, tu vai ad assegnare dei valori
(m_PosX+20, ecc.) ad una zona di memoria che e' sicuramente riservata
alla variabile rect (di tipo RECT questa volta e non puntatore a RECT).
Analogamente passi al metodo Ellipse l'indirizzo della variabile rect,
non un indirizzo casuale.
Per far funzionare anche la seconda versione secondo me puoi usare qualcosa
del tipo seguente:
       RECT* rect;
       rect = new RECT; //alloca una zona di memoria in modo tale che rect
                        //non punti piu' a zero o ad un indirizzo casuale
                        //ma all'indirizzo retituito dalla new.
       if(!rect) funzioneDiGestioneDelleEccezioni();
       rect->left   = m_PosX - 20;
       rect->right  = m_PosX + 20;
       rect->top    = m_PosY - 20;
       rect->bottom = m_PosY + 20;
       pDC->Ellipse(rect);
       delete rect;    //dealloca la zona di memoria puntata da rect.
                       //rendendo il contenuto di rect nuovamente non
                       //significativo (almeno dal punto di vista del
                       //programmatore non sistemista).
NB. Io ho inserito la delete rect dopo la chiamata a Ellipse ma e'
    assolutamente necessario tenere presente che dopo che hai eseguito
    la delete, il contenuto di rect (e quindi l'indirizzo da esso puntato)
    e' da ritenersi nuovamente non significativo nel senso che dopo la
    delete rect non puoi inserire codice tipo
    rect->left = 20;
    perche' avresti gli stessi problemi di prima.
    Quindi la delete va inserita in un punto in cui si e' sicuri che
    il puntatore non verra' piu' utilizzato (almeno non prima di avere
    eseguito un'altra new).
    In particolare e' da tenere ben presente  che la delete va inserita in
    un punto in cui si e' sicuri che essa non venga eseguita due volte
    consecutive (cioe' che non venga eseguita due volte senza che in
    mezzo sia stata eseguita una new).
    Infatti se ad esempio tu scrivessi
    rect = new RECT;
    delete rect;
    delete rect; //tentativo di deallocare una zona di memoria gia'
                 //deallocata => effetti imprevedibili!! Magari il
                 //programma continua a funzionare per poi bloccarsi
                 //improvvisamente in corrispondenza di una delle istruzioni
                 //successive o addirittura in corrispondenza di una delle
                 //esecuzioni successive!!
    D'altra parte la delete va prima o poi eseguita per rilasciare la
    memoria allocata con la new (nel caso che funziona da te prospettato
    la memoria per la variabile rect, di tipo RECT, viene allocata e deallocata
    automaticamente dallo stack, se rect e' una variabile locale di
    qualche funzione. Quindi dallo stack vengono allocati/deallocati
    sizeof(RECT) bytes. Anche nel caso che non funziona da te prospettato
    l'allocazione
    e deallocazione di rect e' automatica ma in questo  caso rect
    e' un puntatore e quindi dallo stack vengono allocati/deallocati 4 bytes
    e, cosa piu' importante, non e' automatica l'allocazione della memoria
    puntata da rect, che in questo caso viene allocata dallo heap e non
    dallo stack).
    Mi sono dilungato veramente molto ma spero di essere stato chiaro visto
    che il problema della allocazione e deallocazione della memoria sembra
    essere uno dei maggiori ostacoli incontrati da chi inizia a programmare
    in C/C++.
    Marco Guidi.
 

 Perchè?
Non funziona perche' rect e' un puntatore e prima di essere utilizzato
si dovrebbe allocare la memoria per esso (in genere con new o
malloc....)
e poi fare le dovute operazioni altrimenti si rischia di fare
operazioni su aree di memoria non ben specificate e che potrebbero
mandare in tilt il sistema!!!!!!!
--
Posted from 
tlvsdy.vim.tlt.alcatel.it
 [151.98.8.244]
via Mailgate.ORG Server - 
http://www.mailgate.org

malloc....)
Lavorando in C++, malloc dovrebbe (in generale) essere evitata a favore
di new (piu` idonea).
Paolo
----------------------------------------------------------
  Paolo Marotta
  Computer Science, University of Pisa
  home:   
http://www.cli.di.unipi.it/~marotta
----------------------------------------------------------