Newsgroup: it.comp.lang.c++
Titolo: Operator NEW e matrici

Devo creare una matrice tridimensionale dinamica di booleani. Qual e' la 
sintassi corretta?
Se scrivo...
const bool * matrice = new bool[dimx][dimy][dimz];
... il compilatore mi mette il broncio. Allora provo ad aggiungere 3 
asterischi, ma il compilatore continua ad odiarmi. Sento che sto 
scazzando di brutto da qualche parte.
-- 
www.project-ring.com

 sintassi corretta?
Leggiti il punto 9 della FAQ:
http://www.emagsoftware.it/faqcpp.htm#9
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg
The EMG Music page:         
http://www.emagsoftware.it/emgmusic

 
http://www.emagsoftware.it/faqcpp.htm#9
Ah, ottimo, grazie!
Allora: ho seguito il tutorial e creato la mia bella matrice 3d di 
booleani in questo modo...
     // Alloco la prima dimensione
     bool * * matrice = new bool * [dimx];
     // Alloco la seconda dimensione
     for (i = 0; i < dimx; i++)
         matrice[i] = new bool [dimy];
     // Alloco la terza dimensione
     for (i = 0; i < dimx; i++)
         for (j = 0; j < dimy; j++)
             matrice[i][j] = new bool [dimz];
A questo punto procedo ad inizializzare a FALSE ogni campo...
     for (i = 0; i < dimx; i++)
         for (j = 0; j < dimy; j++)
             for (k = 0; k < dimz; k++)
                 matrice[i][j][k] = FALSE;
Ma il compilatore mi segnala un errore in quest'ultima riga (e in ogni 
altra che preveda l'accesso a qualsiasi booleano della matrice).
L'errore dice cio': "Invalid types 'bool[int]' for array subscription"
Come mai?
-- 
www.project-ring.com

 L'errore dice cio': "Invalid types 'bool[int]' for array subscription"
Dal momento che c'e' un indice di troppo cerca di interpretare un array
di bool come indice.
Ciao,
Nicola

 > matrice[i][j][k] = FALSE;
il literal corretto è false minuscolo (a meno, ovviamente di typedefs o
#defines).


Il Vampiro Casimiro wrote:
scusa il dubbio, forse dovuto al fatto che ho letto in fretta, 
ma se è una matrice multidimensionale "compatta", perché 
allocarla come se dovesse essere usata come matrice sparsa (e 
quindi iper dinamica e con eventuali buchi per risparmiare spazio) ?
Ti serve realmente uan matrice sparsa ?
Devi risparmiare molto spazio ? Tieni conto che la matrice 
sparsa è più lenta (perché fa tanti calcoli indipendenti di 
dereferencing dei puntatori invece che un solo calcolo 
dell'offset assoluto e un solo dereferenziamento).
Se è applicabile una matrice massiccia, fa una sola allocazione
bool * * * matrice = new bool [dimx] [dimy] [dimz];
se ti serve sparsa, ovviamente, come non detto.
ciao
CCCP++Mario


 se ti serve sparsa, ovviamente, come non detto.
Ciao. Confesso di non conoscere la differenza tra matrice compatta e 
sparsa ^_^
Sto facendo image processing di tomografie assiali al polmone. 
L'immagine iniziale sta su una matrice statica di 512*512*circa300. La 
matrice dinamica che vorrei creare e' un sottoinsieme della stessa che 
costruisco di dimensioni minori possibile per eseguire funzioni su 
agglomerati di voxel non troppo grandi (noduli, per la maggior parte).
-- 
www.project-ring.com

 agglomerati di voxel non troppo grandi (noduli, per la maggior parte).
Non conosco il tuo campo di applicazione, ma sospetto che nel tuo caso
le compattazioni di cui sopra non siano applicabili e quindi
probabilmente ti conviene allocare direttamente una matrice
multidimensionale.
Ciao,
Nicola



Invece di creare una array tridimensionale, puoi crearne uno
unidimensionale, e poi simulare l'accesso alle 3 dimensioni tramite
slice.
Probabilmente troverai delle librerie ottimizzate che usano questo
approccio (in realta' c'e' ne sono per matrici a 2 dimensioni, per 3
dimensioni non saprei).
Il tutto dipende anche da che tipo di operazioni devi fare su queste
matrici.
Saluti  Manlio Perillo

 vale zero.
pensa che avevo la sensazione di avere scritto esattamente la 
stessa cosa che hai scritto tu .... Vabbč, ero stato confuso, ma 
proprio il contrario ....
:-(
cito cmq alcune parti del mio messaggio
<<Se gli array (si riferiva agli sparsi) sono utilizzati 
concretamente, in un dato momento, occupando una bassa 
percentuale di elementi, il risparmio č molto vistoso rispetto 
alla matrice monolitica (che esiste tutta e sempre a 
prescindere), dato che righe, colonne etc etc possono essere 
allocate e deallocate indipendentemente le une dalle altre.>>
<<Se l'occupazione di spazio in termini di elementi usati 
contemporaneamente in un dato momento aumenta ("sempre riferito 
alle sparse, voleva dire se molti elementi non sono nulli e 
inutili"), questa struttura finisce per occupare molto spazio, 
persino di piů della matrice statica (ma č un caso limite, da 
soppesare a priori).>>
da cosa si capisce che ho detto il contrario di quel che č ?
A me sembra solo espresso in modo confuso, ma non il contrario.
Cmq, anche con l'integrazione della tua risposta piů sintetica, 
spero che alla fine il Vampiro abbia capito la questione in 
generale.
Ciao
Soviet-Mario


 [...]
Ciao!
Invece di impazzire con allocazioni/deallocazioni di matrici di bool, ti
propongo questa mia (parzialissima) soluzione, che utilizza un vector<bool>
per memorizzare la matrice e fornisce un'interfaccia abbastanza comoda.
Lo standard propone una versione ad-hoc di vector<> per il tipo bool tale da
ridurre lo spazio di memoria per salvare i singoli "bool". 
Realizzando un wrapper attorno a vector<bool> per rappresentare una matrice
tridimensionale si ottiene un'interfaccia abbastanza user-friendly
ottenendo nel contempo un'uso efficiente della memoria.
Spero che possa servire...
Ciao!
-----------------------------------------------------------------------------
#include <vector>
class Matrix3D
  {
  public:
    typedef std::vector<bool>::reference reference;
    typedef std::vector<bool>::const_reference const_reference;
    Matrix3D( std::size_t x, std::size_t y, std::size_t z ) :
      size_x(x), size_y(y), size_z(z),
      buffer( x * y * z, false )
      {}
    reference operator()( std::size_t x, std::size_t y, std::size_t z )
      { return buffer[ x + size_x * ( y + size_y * z ) ]; }
    const_reference operator()
      ( std::size_t x, std::size_t y, std::size_t z ) const
          { return buffer[ x + size_x * ( y + size_y * z ) ]; }
  private:
    std::size_t size_x, size_y, size_z;
    std::vector<bool> buffer;
  };
int main()
  {
  Matrix3D m(5,5,5);
  bool b = m(4,4,4);
  m(1,2,3) = b;
  m(0,4,2).flip();
  return 0;
  }
-- 
Qual'e' il colmo per uno studente-lavoratore?
Avere un quadrato che si crede un rettangolo.

 della matrice compatta. 
Ecco, allora la compatta e' quella che fa per me, visto che devo 
eseguire soprattutto spostamenti tra elementi contigui.
Le dimensioni cerco di contenerle creando la matrice piu' piccola 
possibile che contenga la regione che devo studiare.
Quindi e' sufficiente dichiararla cosi'...
bool * * * matrice = new bool [dimx] [dimy] [dimz];
E per cancellarla devo scrivere: "delete [dimx][dimy][dimz] matrice" ?
-- 
www.project-ring.com

 :-(
Scusa, non mi sono spiegato bene. Non intendevo dire che hai detto cose
sbagliate, ma che sei partito dal fondo invece che dall'inizio. A me
pare piu' chiaro spiegare prima il concetto dal punto di vista teorico
e poi le soluzioni informatiche.
Ciao,
Nicola

 bool * * * matrice = new bool [dimx] [dimy] [dimz];
Solo chè non funzionne così. A l'allocazione, hai richiesto una
bool[dimx][dimy][dimz]. Perchè s'agisse d'un'allocazione di
tavola, il tipo di l'esspressione diviene bool (*)[dimy][dimz] ;
bisogna que questa sia anchè il tipo della variabile :
    bool (*matrice)[dimy][dimz] = new bool [dimx][dimy][dimz] ;
Chè funzionna solo se dimy e dimz sono costanti. Si non, bisogna
fare:
    bool *matrice = new bool[ dimx * dimy * dimz ] ;
e simularer l'accesso a tre dimensionni :
    matrice[ (x * dimy + y) * dimz + z ]
--
James Kanze                                           GABI Software
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, 
+33 (0)1 30 23 00 34

>

 occupazione di spazio ? Che profondità di "colore" ti serve ?
Be', la matrice dinamica ce l'ho solo con i booleani (la uso ad uno 
stadio del programma in cui non ho piu' bisogno di info sui colori), 
quindi dovrebbe essere ok. Credo. Come e' rappresentato a livello fisico 
un bool?
Per la matrice statica 512*512*300 mi servono solo 8 bit di profondita', 
quindi pensavo di usare i char. Fanno 78 MByte e rotti...
-- 
www.project-ring.com

 Chč funzionna solo se dimy e dimz sono costanti. 
Si', sono costanti.
-- 
www.project-ring.com


ne stai usando 32, ossia il quadruplo del necessario ! Se 
definito in modo standard un bool è una word tipica (con tanti 
bit quanti i plain int, a loro volta determinati 
dall'architettura hardware tipo i registri del processore, che 
immagino essere a 32 bit).
Quantomeno dovresti ridefinire bool o farti una tua typedef dove 
dichiari BOOL come alias per unsigned char, che occupa un byte 
(8 bit).
Sono pensabili anche ulteriori compattazioni che comportino 
l'utilizzo di campi di bit, ma questo ti complica molto il 
codice (serve una classe wrapper che facca da intermediario tra 
i byte, l'unità minima indirizzabile, e i tuoi voxel logici cui 
basta 1 solo bit) e, a fronte di un vantaggio di 7/8 di spazio 
risparmiato, la lentezza d'accesso peggiora molto (non credo sia 
un requisito su cui puoi derogare tanto, con quei volumi di 
voxel da elaborare.
Ah, per delete è sufficiente una sola parentesi quadra, che 
chiama la versione adatta ad aggregati piuttosto che quella per 
singole istanze.
La ragione di tale suddivisione che pare scomoda, penso risieda 
nella maggiore efficacia di implementazione per la versione 
non-array (in quanto non deve tener traccia di quanto spazio è 
stato allocato in quanto è una quantità costante nota in fase di 
compilazione, mentre per la versione array essa è variabile, 
dipendendo da quanti elementi complessivamente son stati 
allocati, non importando invece la struttura dimensionale).
Si potrebbe usare in effetti un unico deallocatore, ma 
costringerebbe a tracciare le dimensioni anche dove non 
necessario .... e se allochi un singolo oggetto grande quanto 
una sola word, lo spreco di spazio raggiunge già altrettanto, 
quindi è inaccettabile.
ciao
Soviet-Mario


 Ah. Mi sto perdendo ^_^.
ahi ahi .... la giustissima precisazione fatta dall'amico 
germanico serve a consentire al compilatore di produrre un 
codice di accesso, tramite puntatore (che di suo non ha 
informazioni di struttura fine della matrice), che permetta il 
corretto calcolo degli indirizzi di ogni elemento e coerente con 
gli indici costanti (tutti eccetto il rightmost, il piů "grande").
Il dichiaratore un po' complicato bool (*matrice)[dimy][dimz] 
definisce un tipo "particolare" di puntatore, il cui 
indirizzamento fornisce un implicito meccanismo statico del 
calcolo degli indici. Dichiaratori simili puoi trovarli utili 
anche nell'uso di puntatori a funzioni
Viceversa se tu vuoi gestire a mano l'indicizzazione nella 
matrice (cosa non impossibile con una piccola funzione inline, 
che magari fa l'overload di () con tre argomenti, basta capire 
bene come pesare gli indici dal leftmost al rightmost), allora 
devi usare un solo asterisco nella creazione bool * matrice.
in qualsiasi caso alla fine basta delete [] matrice;
riciao, passo e chiudo
CCCP++Mario


 Anche la cancellazione cambia oppure rimane: "delete [][][] matrice;"?
Non. Il [] sul delete corresponde più o meno alla conversion del
[] in * sul new. Si T non e tavola, new T da T*, et si usa
delete. Se T est un tavola, cio'è T'*, allora new T == new T'[],
et da T'*, e bisogna di delete[].
Un punto importante : se prende in conto solo il tipo completo
che si alloca. Se il nome del tipo commincia "array[] of ...",
il tipo dell'espressionne new diviene "pointer to ...", e
bisogna di delete[]. C'è massimo una conversione : "array[] of
array[] of ..." devienne "pointer to array[] of ...", e non
"pointer to ..." o "pointer to pointer to ...". Da stesso, si
usa delete[], è non delete[][]. (E in fatto l'errore che hai
fatto quando hai scritto "bool *** matrice = new ...".)
Anche: se prende in considerazione il tipo reale che vede il
compilatore, e non il mode ch'e scritto. Dunque :
    typedef bool TabBool[ 200 ] ;
    bool * p = new TabBool ;  // e non TabBool* p = ...
    delete [] p ;             // e non delete p ;
    int (**p)[ 10 ] = new int (*)[ 10 ] ;
                        // alloca *un* puntatrice a una tavola,
                        // e non una tavola.
    delete p ;          // e non delete [] p.


 voxel da elaborare.
Pero' la libreria standard ne contiene gia' un paio, che sono
std::vector<bool> e std::bitset, che potrebbero fare al caso dell'OP.
Ciao,
Nicola