7

Boost を使用した C++ は初めてです。

クラス "world" のオブジェクトに、"octreenode" 型の "chunk" という名前の配列を持たせたいと考えています。以前は通常の 1 次元配列を使用していましたが、これはうまくいきました。現在、Boost の multi_array 機能を備えた 3D 配列の使用に移行しようとしていますが、何が間違っているのか本当にわかりません。

簡略化されたコード:

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

その後、割り当てを試みた場合

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

エラーが発生します:

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

「octreenode」には関連するコンストラクターがあり、この行は次の場合と同じ構文で機能しました。

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

(一次元配列)。同様に、1 次元配列で正常にコンパイルされたときに、次のような「octreenode」オブジェクトへのポインターを期待する関数にチャンクを渡そうとしました。

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

エラーを生成します

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

どんな提案にも非常に感謝しています。明らかな何かが欠けていると確信しています。

4

1 に答える 1

4

配列は値型 ( octreenode) であり、ポインタ型 ( ) ではありませoctreenode*

newしたがって、動的に割り当てられた octreenode (デフォルトではヒープ割り当て用)にポインターを割り当てようとするべきではありません。

代わりに、値を代入してください:

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

new実際、そもそもマルチ配列で使用する理由もありません。

アップデート

コメントでは、より多くのことを最適化できることが提起されており、コンパイルエラーに関する回答への有用な追加を検討してください。

したがって、次のようになります。実際にすべての配列要素をまったく同じ値で初期化したい場合は、

  1. 配列の形状をしばらく忘れることで、ループをより効率的にすることができます。

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

    octreenodeがPODタイプであることがわかっている場合は、次のように書くことができます

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

    しかし、スマートなライブラリの実装はfill_nとにかく呼び出すことになります (利益がないため)。POD タイプではないuninitialized_fill_n場合に使用できます、簡単に破壊できます。octreenode

  2. 実際、そもそも multi 配列で new を使用する理由もありません。コンストラクターの初期化リストを使用して、 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);
}
于 2015-01-09T20:14:48.790 に答える