View Full Version : [c++] puntatori
struct _ARGB2
{
byte R;
byte G;
byte B;
byte A;
};
typedef _ARGB2* ArgbPtr;
Che differenza c'è tra questo:
_ARGB2 (*_in)[640] = new _ARGB2[480][640];
e questo ?
ArgbPtr *_inPtr = new ArgbPtr[480];
if (_inPtr != null)
{
for (int i = 0; i < 480; i++)
_inPtr[i] = new _ARGB2[640];
e com'è che vanno cancellati ? :help:
questo: _ARGB2 (*_in)[640] = new _ARGB2[480][640]; é sbagliato: il fatto che tu specifichi una costante numerica nella dichiarazione fa si' che l'array di primo livello venga allocato staticamente, quindi in quel caso devi solo allocare gli array di secondo livello.
l'altro invece é corretto ma il controllo dell'if é inutile perché l'operatore new non restituisce mai NULL (in caso di risorse di sistema insufficienti lancia un'eccezione C++ di tipo std::bad_alloc).
per quanto riguarda la deallocazione, il secondo va deallocato all'inverso del primo, cioé iterando sull'array di primo livello e facendo delete su ciascun array di secondo livello ed infine facendo delete sull'array di primo livello. il primo invece non lo so :stordita:
forse devi fare:
delete[][] _in;
ma sono andato ad ipotesi.
Ciao, grazie per la risposta :)
per il primo ho provato con delete [] [] _in; ma da errore, possibile che sia solo delete [] _in; ? perchè il [640] viene cancellato automaticamente ?
per il primo ho provato con delete [] [] _in; ma da errore, possibile che sia solo delete [] _in; ? perchè il [640] viene cancellato automaticamente ? si, puó essere ma ti confesso che non lo so proprio :|
la sintassi che hai usato tu, delete[] _in, si usa per deallocare gli array a una sola dimensione; forse si usa anche per quelli a piu dimensioni.
questa cosa interessa anche a me quindi se ho tempo provo a cercare qualcosa, altrimenti attendo con te un parere piu esperto. :)
struct _ARGB2
{
byte R;
byte G;
byte B;
byte A;
};
typedef _ARGB2* ArgbPtr;
Che differenza c'è tra questo:
_ARGB2 (*_in)[640] = new _ARGB2[480][640];
_in e' un puntatore ad arrays di 640 elementi che viene inizializzato
con un array che contiene 480 di tali elementi.
ArgbPtr *_inPtr = new ArgbPtr[480];
if (_inPtr != null)
{
for (int i = 0; i < 480; i++)
_inPtr[i] = new _ARGB2[640];
_inPtr e' un puntatore a puntatori, che viene inizializzato con un array di puntatori lungo 480. Ogni puntatore viene poi inizializzato con un array di 640 elementi.
La differenza fondamentale sta nella rappresentazione in memoria. Nel primo caso gli array stanno "tutti in fila" nell'array che li contiene, nel secondo caso hai invece dei soli puntatori.
_in :
[[ .... ] [ ... ] [ ... ]]
_inPtr
[[ - ][ - ][ - ]]
| | |
[...] [...] [...]
Se provi il seguente codice:
cout << "sizeof(_in)=" << sizeof(_in) << endl;
cout << "sizeof(_in[0])=" << sizeof(_in[0]) << endl;
cout << "sizeof(_inPtr)=" << sizeof(_inPtr) << endl;
cout << "sizeof(_inPtr[0])=" << sizeof(_inPtr[0]) << endl;
Su una macchina a 32 bit otterrai il seguente output:
sizeof(_in)=4
sizeof(_in[0])=2560
sizeof(_inPtr)=4
sizeof(_inPtr[0])=4
e com'è che vanno cancellati ? :help:
Per quanto visto sopra nel primo caso cancelli solo l'array piu' esterno, nel secondo caso anche quelli interni. Se la mia spiegazione ti ha confuso, segui un altro metodo infallibile: devi distruggere quello che hai allocato, per cui ad ogni new per un singolo oggetto corrisponde una delete, e ad ogni new per un array corrisponde una delete[].:
delete [] _in;
for ( int i=0 ; < 480; ++i )
delete [] _inPtr[i];
delete[] _inPTr;
marco.r, si usa "delete[]" (con una sola coppia di parentesi quadre) anche quando con new si é allocato un array a due o piu dimensioni?
marco.r, si usa "delete[]" (con una sola coppia di parentesi quadre) anche quando con new si é allocato un array a due o piu dimensioni?
Si', perche' per il C++ non si tratta di array a due dimensioni, ma normale.
La peculiarita' del primo e' che gli elementi sono un qualcosa di piu' corposo di un semplice int o float.
Visto che gli array contenuti si trovano "in linea" il compilatore non ha bisogno di far altro che usare la sua dimensione (che e' decisa staticamente e quindi conosce, in questo caso 2560, 640*4) per poter deallocare correttamente l'array puntato da _in;
Si', perche' per il C++ non si tratta di array a due dimensioni, ma normale.
La peculiarita' del primo e' che gli elementi sono un qualcosa di piu' corposo di un semplice int o float.
Visto che gli array contenuti si trovano "in linea" il compilatore non ha bisogno di far altro che usare la sua dimensione (che e' decisa staticamente e quindi conosce, in questo caso 2560, 640*4) per poter deallocare correttamente l'array puntato da _in;mi verrebbe da chiedermi, non sapendo niente di c++, perché esista il delete[] allora, non basta delete? anche lì basta sapere il numero di byte da liberare
mi verrebbe da chiedermi, non sapendo niente di c++, perché esista il delete[] allora, non basta delete? anche lì basta sapere il numero di byte da liberare delete é diverso da delete[] perché se il blocco da cancellare é un array di oggetti devono essere invocati N distruttori, mentre se é un oggetto solo allocato dinamicamente deve essere invocato un distruttore solo.
le due delete in sostanza hanno una semantica diversa: delete senza parentesi quadre assume che tu gli abbia passato un blocco contenente un solo oggetto del tipo puntato, delete[] invece fa un calcolo di quanti oggetti di quel tipo sono contenuti nel blocco di memoria da liberare.
la spiegazione fa schifo ma spero che si comprenda.
ecco, prova per esempio questo codice:
#include <iostream>
using namespace std;
class C {
public:
~C() {
cout << "farewell" << endl;
}
};
int main() {
delete new C[3];
return 0;
}
taluni compilatori potrebbero generarti un eseguibile che stampa "farewell" una volta sola anziché 3. il codice corretto é questo:
#include <iostream>
using namespace std;
class C {
public:
~C() {
cout << "farewell" << endl;
}
};
int main() {
delete[] new C[3];
return 0;
}
mi verrebbe da chiedermi, non sapendo niente di c++, perché esista il delete[] allora, non basta delete? anche lì basta sapere il numero di byte da liberare
Vero ho detto una cosa inesatta :p, in effetti pensandoci la ragione principale non e' tanto la memoria occupata (la free non ha bisogno di dimensioni...), quando la necessita' di sapere su quanti oggetti va chiamato il distruttore.
Faccio un esempio
#include <iostream>
using namespace std;
struct Foo{ ~Foo(){ cout << "bye bye" << endl;} };
int main()
{
Foo* f1 = new Foo[10];
Foo* f2 = new Foo[10];
cout << "delete f1" << endl;
delete f1;
cout << "delete[] f2" << endl;
delete[] f2;
}
L'output del programma e'
delete f1
bye bye
delete[] f2
bye bye
bye bye
bye bye
bye bye
bye bye
bye bye
bye bye
bye bye
bye bye
bye bye
Il succo del discorso non cambia molto cmq. Nel caso del primo array iniziale, basta delete[] perche' gli array contenuti non devono liberare alcuna altra memoria, quella che occupano l'hanno "presa a prestito" dall'array che li contiene.
delete é diverso da delete[] perché se il blocco da cancellare é un array di oggetti devono essere invocati N distruttori, mentre se é un oggetto solo allocato dinamicamente deve essere invocato un distruttore solo.
le due delete in sostanza hanno una semantica diversa: delete senza parentesi quadre assume che tu gli abbia passato un blocco contenente un solo oggetto del tipo puntato, delete[] invece fa un calcolo di quanti oggetti di quel tipo sono contenuti nel blocco di memoria da liberare.
la spiegazione fa schifo ma spero che si comprenda.
Ops, vedo ora che hai gia' risposto correttamente tu.
tnx :D
edit:
ah, secondo voi in un cellulare è meglio usare il primo o il secondo ( o non cambia nente da uno all'altro sui cell nuovi con trecentomillemiggglioni gb di ram ) ?
tnx :D
edit:
ah, secondo voi in un cellulare è meglio usare il primo o il secondo ( o non cambia nente da uno all'altro sui cell nuovi con trecentomillemiggglioni gb di ram ) ? dovresti mettere la semplicitá del codice prima della presunta efficienza: dal momento che conosci giá le dimensioni della matrice da allocare non serve allocarla dinamicamente, é meglio allocarla staticamente perché l'allocazione dinamica é piu difficile da gestire perché devi evitare il leak.
molto difficilmente avrai problemi di performance a causa di simili scelte, se ne dovessi mai avere é solo allora che dovrai refattorizzare, ammesso che la causa sia quella.
tnx :D
edit:
ah, secondo voi in un cellulare è meglio usare il primo o il secondo ( o non cambia nente da uno all'altro sui cell nuovi con trecentomillemiggglioni gb di ram ) ?
E' piu' efficiente il primo metodo, perche' eviti una doppia dereferenziazione e quindi hai un accesso alla ram in meno. Questo vale tanto per il cellulare quanto per il pc desktop.
In generale se uno vuole evitare inefficiente, in C++ evita di allocare un doppio array in questo modo, piuttosto si crea una classe apposita che utilizzi un unico array.
Qualcosa tipo
template <typename T>
class Matrix
{
typedef T& reference;
typedef const T& const_reference;
Matrix(size_t rows,size_t cols ):_nRows(rows),_nCols(cols)
{
_data = new value_type[rows*cols];
}
reference operator()(size_t row,size_t col)
{
assert( row <_nRows );
assert( col < _nCols );
return _data[ _nRows*col + row ];
}
const_reference operator()(size_t row, size_t col) const;
// etc
private:
size_t _nRows;
size_t _nCols;
};
E' piu' efficiente il primo metodo, perche' eviti una doppia dereferenziazione e quindi hai un accesso alla ram in meno. Questo vale tanto per il cellulare quanto per il pc desktop. si ma, ripeto, se le dimensioni sono note a priori (640x480) é inutile usare new e delete, basta semplicemente dichiarare la matrice:
_ARGB2 _in[640][480];
cosi tra l'altro c'é un bel guadagno come tempi di esecuzione perché si evita la chiamata all'operatore new e successivamente quella all'operatore delete; a voler fare proprio i pignoli qualche millesimo di secondo secondo me lo risparmi :D
si ma, ripeto, se le dimensioni sono note a priori (640x480) é inutile usare new e delete, basta semplicemente dichiarare la matrice:
_ARGB2 _in[640][480];
cosi tra l'altro c'é un bel guadagno come tempi di esecuzione perché si evita la chiamata all'operatore new e successivamente quella all'operatore delete; a voler fare proprio i pignoli qualche millesimo di secondo secondo me lo risparmi :D
c'è un problema (almeno con samsung bada non so con gli altri so per cellulari) se si fa così funziona solo nel simulatore e crasha sul telefono perchè l'array non sta nello stack :fagiano:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.