实例化后更改multi_array_ref数据块

时间:2018-08-07 17:20:38

标签: c++ multidimensional-array boost

我一直在试验boost multi_array_refs,因为它们能够将世界的2D(以我为例)阵列视图映射到连续内存的任意块上。使用multi_array_ref时,将指向连续内存的指针指定给构造函数。效果很好,但是在我的最终应用程序中,我真正想做的是获取一个预先存在的multi_array_ref对象,并将其指向动态分配的新缓冲区。似乎应该可行,但是我似乎不知道该怎么做。我希望这里有一些基本代码可以演示我要尝试做的事情的类型,尽管它显然不能按编写的方式工作。

const int XSIZE = 10;
const int YSIZE = 5;

typedef boost::multi_array_ref<int, 2> ARRAY_2D_REF;

class Test2D {
public: 
   Test2D(const int sizeX, const int sizeY);
   ~Test2D();

   // I want to point this multi_array_ref to a buffer that gets
   // allocated in the constructor.
   ARRAY_2D_REF data;

private:
   int  xSize;
   int  ySize;
   int  *n;
};

// can't construct 'data' using ':' syntax here, because, the 'n'
// buffer has not been allocated yet so 'n' doesn't contain a valid
// address. This compiles okay, but segfaults if you try to use 'data'
// because 'n' contains garabge at this point.
Test2D::Test2D(const int sizeX, const int sizeY) : data(n, boost::extents[sizeX][sizeY])  // <<-- fail
{
   xSize = sizeX;
   ySize = sizeY;

   // In the actual application, n will be populated by data arriving
   // on TCP stream. The header on those mesasges contain total
   // contiguous buffer size and X,Y dimensions, followed by the data.
   n = (int*)malloc(xSize * ySize * sizeof(int));

   // I want to set the multi_array_ref origin and define extents right
   // here. The thought was to set the origin to 'n', and then
   // resize(), but how?  Of course I can't actually construct it here
   // as shown.  Seems like there should be a simple way to set
   // (change) the origin pointer. There probably is in fact. But I
   // can't seem to figure it out.
   data(n, boost::extents[xSize][ySize]);
}

1 个答案:

答案 0 :(得分:0)

初始化器列表中的初始化器按照类成员(基类之后的成员)的声明顺序进行求值。

因此,您可以通过将data成员声明移到其他成员之后来解决所有问题。

#include <boost/multi_array.hpp>

static const int XSIZE = 10;
static const int YSIZE = 5;

typedef boost::multi_array_ref<int, 2> ARRAY_2D_REF;

class Test2D {
  public: 
    Test2D(const int sizeX, const int sizeY)
      : xSize(sizeX),
        ySize(sizeY),
        n (new int[xSize*ySize]),
        data(n, boost::extents[xSize][ySize])
    { }

    ~Test2D() {
        delete n;
    }

    Test2D(Test2D const&) = delete; // Rule Of Three!

  private:
    int  xSize;
    int  ySize;
    int  *n;
  public:
    ARRAY_2D_REF data;
};

int main() {
    Test2D wrapped(XSIZE, YSIZE);
}

注意

  • 在C ++中没有malloc的地方
  • 您应防止复制该类型,否则将对数据缓冲区进行两倍{delete}。

其他想法

如果您的评论说,从构造函数内部分配缓冲区(无论是body还是initializer-list),实际上没有任何意义。

//在实际的应用程序中,n将由到达的数据填充    //在TCP流上。这些消息的标题包含总计    //连续的缓冲区大小和X,Y维度,后跟数据。

构造函数没有进行分配所必需的依赖关系,也不应该进行分配。有两种选择:

  • 如果缓冲区始终由Test2D实例拥有(并且将从IO缓冲区复制数据),则只需使用multi_array,不是multi_array_ref 。它会安全地为您分配资源。

  • 否则,传入缓冲区:

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

static const int XSIZE = 10;
static const int YSIZE = 5;
static const int HEADER_SIZE = 16;

typedef boost::const_multi_array_ref<int, 2> ArrayCRef;

class Test2D {
  public: 
    Test2D(int const* raw, int sizeX, int sizeY) : data(raw, boost::extents[sizeX][sizeY])
    { }

    ArrayCRef::size_type xSize() const { return data.shape()[0]; }
    ArrayCRef::size_type ySize() const { return data.shape()[1]; }
  public:
    ArrayCRef data;
};

int main() {
    auto io_buf = std::make_unique<char[]>(XSIZE*YSIZE*sizeof(int)+HEADER_SIZE);

    // TODO parse XSIZE/YSIZE from io_buf
    auto raw = reinterpret_cast<int const*>(io_buf.get() + HEADER_SIZE);

    Test2D wrapped(raw, XSIZE, YSIZE);
}