View Full Version : Una delucidazione in C++
qual'è la differenza secondo voi tra queste 2 dichiarazioni?
a) TPanel** Panel = new TPanel*[100];
b) TPanel* Panel = new TPanel[100];
ilsensine
06-11-2001, 21:22
La prima alloca un array di 100 puntatori a oggetti TPanel, la seconda alloca un array di 100 oggetti TPanel
so che hai usato bcb; quindi ti chiedo:
a) TImage** Image = new TImage*[100];
b) TImage* Image = new TImage[100];
io devo allocare dinamicamente dei TImage facendo in modo che con delete[] all'uscita dell'aplicazioni venga liberata completamente la memoria.
Avevo scritto una cosa tipo:
c) TImage *Image[100];
in questo caso specifico mi hanno riferito che la chiamata a delete[] nel momento in cui desidero eliminare un elemento della matrice e deallocare la memoria è inutile in quanto vengono deallocati solo i punatori.
Ho provato le tre soluzioni (a/b/c) ma il risultato che ottengo apparentemente è il medesimo.
Sai qualcosa a tal proposito?
Grazie
Originariamente inviato da misterx
aggiungo questo scorcio di programma che mostra su una form delle immagini ridimensionate; una sorta di anteprima.
int x=0,y=0;
TImage *Image[100]; // qui è l'errore
for (int i =0; i <FileListBox1->Items->Count; i++)
{
x+=105;
if(x>=105*5) {x=0;y+=105;}
Image[i] = new TImage(Form1);
Image[i]->Top = 5;
Image[i]->Left = 5;
Image[i]->Stretch = true;
Image[i]->Width = 90;
Image[i]->Height = 90;
Image[i]->Parent = Form1;
Image[i]->Picture->LoadFromFile(FileListBox1->Items->Strings[i]);
}
Grazie
/\/\@®¢Ø
06-11-2001, 23:39
Originariamente inviato da misterx
[B]so che hai usato bcb; quindi ti chiedo:
a) TImage** Panel = new TImage*[100];
b) TImage* Panel = new TImage[100];
io devo allocare dinamicamente dei TImage facendo in modo che con delete[] all'uscita dell'aplicazioni liberi completamente la memoria.
Avevo scritto una cosa tipo:
c) TImage *Image[100];
in questo caso specifico mi hanno riferito che la chiamata a delete[] nel momento in cui desidero eliminare un elemento della matrice e deallocare la memoria è inutile in quanto dealloca solo i punatori.
Ho provato le tre soluzioni (a/b/c) ma il risultato che ottengo apparentemente è il medesimo.
Sai qualcosa a tal proposito?
Grazie
Ciao.
Nel primo caso allochi effettivamente un array di 100 puntatori. Di conseguenza devi creare poi dinamicamente gli ogggetti uno ad uno. Ad esempio con
for ( int i=0 ; i<100; i++ )
Image[i] = new TImage;
Di conseguenza quando devi eliminare il tutto devi pure fare l'opposto. Eliminare i cento puntatori col delete e poi fare il delete[] sull'array.
con b) invece viene allocato dinamicamente un array di 100 oggetti. Quando fai delete[] sull'array viene chiamato il distruttore per ognuna delle cento istanze e quindi non occorre fare altro.
ancora piu' semplice con c). L'array e' allocato staticamente e non occorre elimiarlo. Gli oggetti vengono eliminati alla chiusura del programma.
a) e' piu' scomodo pero' ha il pregio che puoi inizializzare gli oggetti con costruttori diversi da quelli di default.
a) TImage** Panel = new TImage*[100];
b) TImage* Panel = new TImage[100];
c) TImage *Image[100];
tra le dichiarazioni (a/c) ottengo solo una differenza di prestazioni del programma.
Ho compilato il programma usando la dichiarazione (a) e poi (b); ho eliminato tutti i delete/delete[] per capire se la memoria allocata viene deallocata automaticamente da codice aggiunto dal compilatore.
Ebbene: in entrambi i casi, la memoria viene liberata senza la necessità di richiamare alcun distruttore.
Non ho capito perchè.
ilsensine
07-11-2001, 09:09
ancora piu' semplice con c). L'array e' allocato staticamente e non occorre elimiarlo. Gli oggetti vengono eliminati alla chiusura del programma.
Attenzione, anche c) dichiara un array di 100 puntatori ;)
Un array di 100 oggetti dovrebbe essere creato con
TImage Images[100];
marco
in tutte le mie dichiarazioni non c'è alcun bisogno di deallocare la memoria in quanto mi hanno riferito che nelle specifiche della VCL è compresa la deallocazione automatica.
Beh, si lavora meno...
Grazie ancora anche a ilsensine
Ciao
/\/\@®¢Ø
07-11-2001, 23:35
Originariamente inviato da ilsensine
[B]
Attenzione, anche c) dichiara un array di 100 puntatori ;)
Un array di 100 oggetti dovrebbe essere creato con
TImage Images[100];
Ops... hai ragione :)
e per rendere l'array dinamico?
anzichè 100 elementi un numero indefinito?
int x=0,y=0;
TImage *Image[???];
for (int i =0; i <FileListBox1->Items->Count; i++)
{
x+=105;
if(x>=105*5) {x=0;y+=105;}
Image[i] = new TImage(Form1);
Image[i]->Top = 5;
Image[i]->Left = 5;
Image[i]->Stretch = true;
Image[i]->Width = 90;
Image[i]->Height = 90;
Image[i]->Parent = Form1;
Image[i]->Picture->LoadFromFile(FileListBox1->Items->Strings[i]);
}
ilsensine
08-11-2001, 20:01
TImage **Image = (TImage**) malloc (sizeof(TImage*)*FileListBox1->Items->Count);
(...fai quello che devi fare...)
free(Image)
Scusa per il malloc, ma ci sono rimasto affezionato :D ;)
ottimo ilsensine; ora sono alle prese con le variabili locali/globali;
se la tua dichiarazione la metti localmente in una funzione, le altre funzioni non possono accedere agli Image dichiarati in essa.....
se sposti la tua dichiarazione nell'header, si rifiuta di compilarla.....
manca sempre 30 a fare 31.:confused:
ilsensine
08-11-2001, 21:13
Dichiara TImage **Image in un file c (fuori dalle funzioni), e in un header dichiari
extern TImage **Image;
/\/\@®¢Ø
08-11-2001, 21:16
Devi mettere la semplice dichiarazione nell'header, e poi definirla in un solo file.
Ad esempio, se voglio avere un array di questi oggetti:
nell'header:
extern TImage** Image;
in un file .cpp
TImage** Image = new TImage* [blabla->count];
ho già provato ma il linker mi dice che non trova le definizioni degli altri componenti....
ilsensine
08-11-2001, 21:18
TImage** Image = new TImage* [blabla->count];
Ehm...è un pò difficile mettere questa riga (compreso il new) fuori da una funzione ;)
/\/\@®¢Ø
08-11-2001, 21:19
non vale !
mi hai anticipato ancora !
uffi !:mad:
:D
/\/\@®¢Ø
08-11-2001, 21:21
porc... toppato ancora :eek:
dovrei avere un po' meno fretta nello scrivere :)
ilsensine
08-11-2001, 21:21
Ehm...è un pò difficile mettere questa riga (compreso il new) fuori da una funzione
Ariehm...ho detto una c@zz@t@ :D
(o meglio, si può usare una new con parametro di array costante, ma non variabile ovviamente)
/\/\@®¢Ø
08-11-2001, 21:26
Fiuu... ogni tanto le intivo allora ! :)
Da un certo punto di vista hai ragione comunque. In quella funzione devi fare riferimento a valori che siano gia' noti, e non sempre la cosa e' immediata ( se utilizzi costanti che stanno in altri files .cpp potrebbero non essere ancora state inizializzate ).
Forse la cosa migliore sarebbe quella di utilizzare funzione opportuna
TImage** Image = new TImage* [blabla->count];
questo alloca degli oggetti TImage giusto?
ma ho notato che beve parecchia memoria
e cosi?
TImage* Image = new TImage [blabla->count];
/\/\@®¢Ø
08-11-2001, 22:26
il primo non alloca gli oggetti. Alloca solo la memoria per i puntatori.
Poi devi fare per ogni casella
Image[i]= new TImage;
e alla fine
delete Image[i]
per ogni i prima di fare il
delete[] Image;
Si'. consuma piu' memoria perche' oltre all'oggetto ci vuole lo spazio per il puntatore. Sui nostri pc questo vuol dire 32bit in piu' per ogni oggetto che vuoi creare.
Attento che come ha fatto osservare ilsensine il campo blabla->count deve essere inizializzato ad un valo
re priam dell'inizio del programma ( ad esempio peche' e' una struttura con valore costante ).
Se il valore te lo ricavi durante l'elaborazione, ti conviene non farlo puntare a niente con
TImage ** Image = 0; // (*)
e poi inizializzarlo con la new durante l'esecuzione del programma, quando sai la dimensione effettiva.
Non puoi comunque evitare il punto (*) perche' devi dire al compilatore in che files vuoi gestire l'inizializzazione dell'array.
Spero di non averti confuso le idee :)
partendo da quanto illustarto da ilsensine
qui viene allocato un array di 100 puntatori a oggetti TImage (4 byte x pointer)
a) TImage** Image = new TImage*[100];
qui viene allocato un array di 100 oggetti TImage (188 byte per TImage, valore ottenuto da sizeof(TImage))
b) TImage* Image = new TImage[100];
caso (a)
TImage** Image = new TImage*[100];
for (int i =0; i <FileListBox1->Items->Count; i++)
{
Image[i] = new TImage(Form1);
Image[i]->Picture->LoadFromFile(FileListBox1->Items->Strings[i]);
}
caso (b)
TImage* Image = new TImage[100];
for (int i =0; i <FileListBox1->Items->Count; i++)
{
Image[i] = new TImage(Form1);
Image[i]->Picture->LoadFromFile(FileListBox1->Items->Strings[i]);
}
nel caso (b) la chiamata "Image[i] = new TImage(Form1);" non è inutile?
in quanto gli oggetti sono stati già creati all'esecuzione del programma?
quindi il caso (b) diverrebbe:
caso (b) senza il costruttore
TImage* Image = new TImage[100];
for (int i =0; i <FileListBox1->Items->Count; i++)
{
Image[i]->Picture->LoadFromFile(FileListBox1->Items->Strings[i]);
}
sicuramente avrò scritto l'ennesima cappellata.....
ilsensine
09-11-2001, 12:01
Invece è corretto. Ricorda che con new puoi anche invocare uno specifico costruttore; ad es. puoi cambiare questo
Image* Image = new TImage[100];
con
TImage *Image;
(...)
Image = new TImage[quellochevuoi](Form1);
(...)
delete [] Image;
Se TImage *Image la rendi globale, potrai accedervi anche da altre parti.
ho parlato forse troppo presto; il compilatore rifiuta questo metodo
TImage* Image = new TImage[100];
for (int k =0; k <FileListBox1->Items->Count; k++)
{
Image[k]->Picture->LoadFromFile(FileListBox1->Items->Strings[k]);
}
non si può allocare preventivamente gli oggetti.....boh....
ecco cosa si ottiene.......
Cannot find default constructor to initialize array element of type 'class'
When declaring an array of a class that has constructors, you must either explicitly initialize every element of the array, or the class must have a default constructor.
The compiler will define a default constructor for a class unless you have defined any constructors for the class.
ilsensine
09-11-2001, 15:46
Cannot find default constructor to initialize array element of type 'class'
Chettepoxxx
Image = new TImage[100](Form1);
Originariamente inviato da ilsensine
[b]
Chettepoxxx
Image = new TImage[100](Form1);
scusa se insisto ma non funziona......
già che ti ho fatto perdere la pazienza, un'ultima curiosità:
abbiamo detto che (a) e (c) sono equivalenti;
a) TImage** Panel = new TImage*[100];
b) TImage* Panel = new TImage[100];
c) TImage *Image[100];
entrambi allocano solo dei puntatori quindi, tanto per capire, è come se io scrivessi:
per il caso (a) e (c): char *buf[100];
e per il caso (b): char buf[100][80];
abbi pazienza
/\/\@®¢Ø
09-11-2001, 23:16
Originariamente inviato da ilsensine
[B]
Image = new TImage[100](Form1);
Non sapevo si potesse fare cosi'.
E' possibile che non sia una notazione dello standard C++ ma una qualche estensione del compilatore che usi ?
Da quello che so...non è C++ standard...la new dovrebbe permettere di utilizzare esclusivamente il costruttore di default (senza parametri)...
Originariamente inviato da /\/\@®¢Ø
[B]
Non sapevo si potesse fare cosi'.
E' possibile che non sia una notazione dello standard C++ ma una qualche estensione del compilatore che usi ?
scusa, ma questo "Image = new TImage[100](Form1); " non me lo permette in quanto il compilatore mi dice che gli oggetti devono essere inizializzati, forse aggiungendo ulteriore codice che attualmente mi sfugge
ilsensine
10-11-2001, 13:16
Non so se devi usare una sintassi particolare...col g++ della gnu funziona (ovviamente devi eseguirla dentro a una funzione, e non in una eventuale dichiarazione globale di Image).
Originariamente inviato da ilsensine
[B]Non so se devi usare una sintassi particolare...col g++ della gnu funziona (ovviamente devi eseguirla dentro a una funzione, e non in una eventuale dichiarazione globale di Image).
non è che casualmente sai come si fa ad ottenere il valore di ritorno da:
Image1->Picture->LoadFromFile("");?
mi interesserebbe sapere in quanto alcune volte, in caso di file corrotti, viene visualizzato un errore interno.
E' possibile scansarlo per poter continuare?
ilsensine
10-11-2001, 21:01
Se l'errore di lettura genera una eccezione, te la cavi con un blocco try...catch
Originariamente inviato da ilsensine
[B]Se l'errore di lettura genera una eccezione, te la cavi con un blocco try...catch
avevo supposto una cosa del genere leggendo nella documentazione ma....
come si implementa?
ho trovato questo:
void __fastcall TForm1::ThrowException(TObject *Sender)
{
try
{
throw Exception(“VCL component”);
}
catch(const Exception &E)
{
ShowMessage(AnsiString(E.ClassName())+ E.Message);
}
}
ilsensine
11-11-2001, 00:02
Si implementa esattamente come nell'esempio:
try {
Image1->Picture->LoadFromFile(filename);
} catch (const Exception &E) {
// gestione delle eccezioni vcl
} catch (...) {
// gestione delle altre eccezioni (non dovrebbero accadere)
}
così funziona egergiamente se il rpogramma viene lanciato furi dall'ambiente di sviluppo, in pratica viene visualizzato un frame vuoto.....
try {
Image1->Picture->LoadFromFile(filename);
} catch (const Exception &E) {
}
fino a qui mi sta bene ma:
come si legge il valore o l'eccezione per potersi comportare di conseguenza?
io vorrei fare un cosa del tipo:
if(Exception !) NULL) {
printf("hai dei file corrotti");
//altro codice
}
else {
printf("i tuoi file sono tutti OK");
//altro codice
}
Solitamente Exception permette di recuperare i codice di eccezione...
Basta fare uno switch o una serie di if da quello...
trovato, la solita fretta; cattiva consigliera:)
try {
Image[i]->Picture->LoadFromFile(miofile);
} catch (const Exception &E) {
ShowMessage(AnsiString(E.ClassName())+ E.Message);
}
questa è interessante almeno x me; se ne sapete qualcosa a riguardo, dite; grazie.
try {
Image[i]->Picture->LoadFromFile(miofile);
}
catch (...) { // questo punto; cioè -> (...) <-
}
significa forse considera tutte le eccezioni?
oppure ignora tutte le eccezioni?
ilsensine
12-11-2001, 20:33
Vuol dire: cattura tutte le eccezioni che non sono state eventualmente catturate da altri blocchi catch. Se usato da solo ovviamente ti cattura tutte le eccezioni, ma non puoi capire di che tipo di eccezione si tratta.
grazie per la tua risposta.
Ancora un chiarimento; guarda questa porzione di codice:
se in luogo della funzione LoadFromFile() del BCB ne utilizzo una presente in una DLL esterna, l'errore generato dalla DLL si comporta come se disabilitasse la cattura delle eccezioni del blocco try/catch.
Ti sembra un fatto normale?
Scusa se utilizzo un esempio banale ma è come se l'errore generato dalla DLL es: "file corrotto" avesse una sorta di priorità sulle eccezioni quindi l'applicazione si blocca.
try {
Image[i]->Picture->MiaFunzPersonale(miofile);
}
catch (...) { }
ilsensine
12-11-2001, 22:19
Smanettando (smadonnando) con le opzioni sulla gestione delle eccezioni del bcb dovresti riuscire a catturare anche le eccezioni delle dll
Originariamente inviato da ilsensine
[B]Smanettando (smadonnando) con le opzioni sulla gestione delle eccezioni del bcb dovresti riuscire a catturare anche le eccezioni delle dll
smadonnando:D :D :D
anche se non sono romano....ammazaho...gaiardo:D :D :D
porc.....ridendo e scherzando tra le opzioni del BCB non trovo nulla a riguardo..
ilsensine
14-11-2001, 13:13
Mi riferisco alle opzioni sotto Tools->Debugger Options. Se ti può consolare non ho mai capito bene come usarle (se qualcuno lo sa si faccia avanti), ma smanettando un pò sono riuscito a catturare le eccezioni anche se compariva comunque un messaggio di errore di windows. Non mi chedere come ho fatto però perchè non me lo ricordo ;)
Originariamente inviato da ilsensine
[b]Mi riferisco alle opzioni sotto Tools->Debugger Options. Se ti può consolare non ho mai capito bene come usarle (se qualcuno lo sa si faccia avanti), ma smanettando un pò sono riuscito a catturare le eccezioni anche se compariva comunque un messaggio di errore di windows. Non mi chedere come ho fatto però perchè non me lo ricordo ;)
grazie, ti avevo capito; ho trovato ma non so se è giusto [-x]
mah....
guarda questo scorcio di programma che dovrebbe filtrare le immagini bacate:
ritval = ImpFunc(FileListBox1->Items->Strings[nf].c_str(),false);
if(ritval != NULL) // se lettura ok, incremento
{
x+=105;
if(x>=105*3) {x=0;y+=105;}
i++;
}
else // se lettura non ok elimino
{
ListBox1->Items->Add(FileListBox1->Items->Strings[i]);
delete Image[i];
MoveFile(FileListBox1->Items->Strings[i].c_str(),AnsiString("bug\\"+FileListBox1->Items->Strings[i]).c_str());
}// end if(ritval != NULL)
come vedi, in caso di immagine corrotta cerco di muoverla in un'altra directory, solo per capire come cavolo funziona la DLL da me trovata.
Bene, nel caso in cui la DLL fa apparire il suo malefico BOX con il relativo messaggio di errore ho un (ritval) valido e di conseguenza questa porzione di codice viene saltata, anche se il file in questione è corrotto.
E' ancora un pò incasinato ma è in fase di sviluppo...
Se si riuscisse con le eccezioni ad inibire questo messaggio ed al suo posto piazzarci il mio......:(
ilsensine
15-11-2001, 09:21
Se la cattura della eccezione la fai nella dll, è lì il problema - francamente non ho mai provato a vedere che succede se l'eccezione la ricatturo nella stessa dll (intendo se bisogna compilarla con accortezze particolari). Mi hai fatto venire la curiosità...
ps la dll la linki staticamente o la carichi con LoadLibrary?
Originariamente inviato da ilsensine
[B]Se la cattura della eccezione la fai nella dll, è lì il problema - francamente non ho mai provato a vedere che succede se l'eccezione la ricatturo nella stessa dll (intendo se bisogna compilarla con accortezze particolari). Mi hai fatto venire la curiosità...
ps la dll la linki staticamente o la carichi con LoadLibrary?
la uso dinamicamente usando LoadLibrary() in quanto i file (.lib e .h) non li possiedo...
Il problema maggiore è che la comparsa del messaggio di errore mostrato dalla DLL non mi permette di debuggare in modo corretto...
cmq, in parte ho risolto e poi, ad una DLL freeware forse non si può chiedere di +:)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.