7

Soy bastante nuevo en C++ con Boost.apunta a una clase en el boost distribuido dinámicamente multi_array, sin compilar

Quiero que un objeto de clase "world" tenga una matriz llamada "chunk" de tipo "octreenode". Anteriormente tenía una matriz unidimensional ordinaria, y esto funcionó bien. Ahora estoy tratando de pasar a usar una matriz 3D con la funcionalidad multi_array de Boost, y realmente no estoy seguro de lo que estoy haciendo mal.

código simplificado:

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); 
     } 
     } 
    } 
    } 
}; 

Después de lo cual si intento realizar la asignación

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

me sale el error:

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

"octreenode" tiene el constructor correspondiente, y esta línea funcionó en sintaxis idéntica cuando era solo:

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

(con una matriz unidimensional). Del mismo modo, mientras que compila bien con una matriz unidimensional, tratando de pasar el trozo de funciones que esperan un puntero a un objeto "octreenode", tales como:

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

genera el error

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

Estaría muy agradecido por cualquier sugerencia, estoy seguro de que me falta algo obvio.

+0

(la sugerencia de eliminación de referencias "trozo" vinieron específicamente de https: // grupos .google.com/forum /? fromgroups = #! topic/boost-list/IWKIdlrg4dU) – Riot

Respuesta

4

Su matriz es de tipo de valor (octreenode), no Tipo de puntero (octreenode*)

Por lo tanto, no se supone que tratar de asignar un puntero a una octreenode asignada dinámicamente (new es para asignación del montón, por defecto) .

En cambio, sólo asignar un valor:

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

De hecho, no hay razón para usar new en la matriz multi en el primer lugar, ya sea:

ACTUALIZACIÓN

En los comentarios que se ha planteado que se podrían optimizar más cosas y que se consideran útiles las adiciones a la respuesta sobre el error de compilación.

así que aquí va: si en verdad desea inicializar todos los elementos de la matriz con el mismo valor exacto,

  1. Puede realizar los bucles de manera más eficiente por olvidarse de las formas de la matriz por un momento:

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

    Si conoces octreenode es un tipo POD, que podría escribir

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

    pero una implementación inteligente de la biblioteca terminaría llamando al fill_n de todos modos (porque no hay ganancia). Puede usar uninitialized_fill_n si octreenode es no un tipo POD, pero es trivially destructible.

  2. De hecho, tampoco hay ninguna razón para usar nuevo en la matriz múltiple en primer lugar. Usted sólo puede utilizar la lista de inicialización de constructores para construir el miembro de 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

Desde que hace unos años pregunté esto, es un poco difícil recordar el contexto, pero la matriz múltiple se está declarando rojo en el montón porque era demasiado grande para la pila; el deseo de tener los fragmentos simultáneos en la memoria era la intención detrás de asignar la matriz múltiple de no punteros en el montón, en lugar de una matriz de punteros que podría estar por todas partes, y podría alterar el caché mientras desreferencia e iteración. Sin embargo, puedo ver mirando hacia atrás ahora que mi intento de "nuevo octreenode" de esa manera fue extraviada, y debería haber usado la forma de ubicación de nuevo. Voy a publicar una respuesta. – Riot

+0

Mmm. Supongo que esto me enseña a mantenerme alejado de la cola "sin respuesta" ... – sehe

+2

¡Espero que no! Tu respuesta me llevó a volver a visitar esto, y espero que esta discusión sea útil para alguien que venga de google en el futuro. – Riot

Cuestiones relacionadas