7

Sono abbastanza nuovo a C++ con Boost.puntatori a una classe in multi_array boost allocata dinamicamente, non compilando

Desidero che un oggetto del "mondo" di classe abbia un array denominato "chunk" di tipo "octreenode". Precedentemente avevo un ordinario array monodimensionale, e questo ha funzionato bene. Ora sto cercando di passare all'utilizzo di un array 3D con la funzionalità multi_array di Boost e non sono sicuro di cosa sto facendo male.

codice semplificato:

class world { 
public: 

    typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks 
    typedef planetchunkarray::index index; 
    planetchunkarray *chunk; 

    world(double x,double y,double z, 
     int widtheast, int widthnorth, int height) : 
     originx(x), originy(y), originz(z), 
     chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height) { 

    chunk = new planetchunkarray(boost::extents[chunksnorth][chunkseast][chunksup]); 
    planetchunkarray::extent_gen extents; 

    for (int cz = 0; cz < chunksnorth; ++cz) { 
     for (int cx = 0; cx < chunkseast; ++cx) { 
     for (int cy = 0; cy < chunksup; ++cy) { 
      (*chunk)[cz][cx][cy] = new octreenode(1,72); 
     } 
     } 
    } 
    } 
}; 

Dopo di che, se tento di eseguire l'assegnazione

root->planet[0]->chunk[0][0][0]->material = 4;

ottengo l'errore:

error: base operand of '->' has non-pointer type 'boost::detail::multi_array::sub_array<octreenode, 1u>'| 

"octreenode" ha il costruttore in questione, e questa linea ha funzionato in sintassi identica quando era giusta:

root->planet[0]->chunk[0]->material = 4;

(con una matrice unidimensionale). Analogamente, mentre compilato bene con una matrice unidimensionale, cercando di passare il pezzo di funzioni che prevedono un puntatore a un oggetto "octreenode", come ad esempio:

compactoctree(root->planet[p]->chunk[cz][cx][cy], 0, 14);

genera l'errore

error: cannot convert 'boost::detail::multi_array::sub_array<octreenode, 1u>' to 'octreenode*' for argument '1' to 'short int compactoctree(octreenode*, int, int)'| 

Sarei molto grato per qualsiasi suggerimento, sono sicuro che mi manca qualcosa di ovvio.

+0

(suggerimento di dereferenziazione "chunk" appositamente venuto da https: // gruppi .google.com/forum /? fromgroups = #! topic/boost-list/IWKIdlrg4dU) – Riot

risposta

4

tuo array è di tipo di valore (octreenode), non è tipo puntatore (octreenode*)

Pertanto non si dovrebbe cercare di assegnare un puntatore a un octreenode allocata dinamicamente (new è per l'allocazione heap, per impostazione predefinita) .

Invece, assegnare un valore:

 (*chunk)[cz][cx][cy] = octreenode(1,72); 

In realtà, non c'è alcuna ragione per usare new sul multi array in primo luogo uno:

UPDATE

Nelle osservazioni è stato sollevato il fatto che più cose potrebbero essere ottimizzate e che tu consideri utili aggiunte alla risposta sull'errore di compilazione.

quindi ecco qui: se davvero desidera inizializzare tutti gli elementi di un array con lo stesso valore esatto,

  1. È possibile effettuare le anse modo più efficiente dimenticare le forme di array per un attimo:

    std::fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72}); 
    

    Se si conosce octreenode è un tipo POD, si potrebbe scrivere

    std::uninitialzed_fill_n(chunk.data(), chunk.num_elements(), octreenode {1, 72}); 
    

    ma un'implementazione di libreria intelligente finirebbe a chiamare comunque fill_n (perché non c'è alcun guadagno). È possibile utilizzare uninitialized_fill_n se octreenode è non un tipo POD, ma è è banalmente distruttibile.

  2. In effetti, non c'è motivo di utilizzare nuovi sul multi array in primo luogo. Si può semplicemente utilizzare la lista di inizializzazione del costruttore per costruire il membro multi_array


Live On Coliru

#include <boost/multi_array.hpp> 
#include <type_traits> 

struct octreenode { int a; int b; }; 

class world { 
public: 
    world(double x, double y, double z, int widtheast, int widthnorth, int height) 
      : 
       originx(x), originy(y), originz(z), 
       chunkseast(widtheast), chunksnorth(widthnorth), chunksup(height), 
       chunk(boost::extents[chunksnorth][chunkseast][chunksup]) 
    { 
     octreenode v = { 1, 72 }; 
     std::fill_n(chunk.data(), chunk.num_elements(), v); 
    } 

private: 
    double originx, originy, originz; 
    int chunkseast, chunksnorth, chunksup; 

    typedef boost::multi_array<octreenode, 3> planetchunkarray; // a boost_multi for chunks 
    typedef planetchunkarray::index index; 
    planetchunkarray chunk; 
}; 

int main() { 
    world w(1,2,3,4,5,6); 
} 
+0

Dal momento che ho chiesto questo a pochi anni fa è un po 'difficile ricordare il contesto, ma il multi-array è in fase di decla rosso sull'heap perché era troppo grande per lo stack; il desiderio di avere i blocchi concomitanti in memoria era l'intenzione di allocare il multi-array di non-puntatori all'heap, piuttosto che una serie di puntatori che potevano essere dappertutto, e avrebbe distrutto la cache durante il dereferenziamento e l'iterazione. Tuttavia, posso vedere guardando indietro ora che il mio tentativo di "nuovo octreenode" in quel modo era fuori luogo, e avrei dovuto usare il modulo di collocamento di nuovo. Posterò una risposta – Riot

+0

Mmm. Credo che questo mi insegna a stare lontano dalla coda "senza risposta" ... – sehe

+2

Spero di no! La tua risposta mi ha spinto a rivederlo, e spero che questa discussione sarà utile a qualcuno che verrà da Google in futuro. – Riot

Problemi correlati