【问题标题】:Changing multi_array_ref data block after instantiation实例化后更改 multi_array_ref 数据块
【发布时间】:2019-01-14 20:47:02
【问题描述】:

我一直在尝试使用 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]);
}

【问题讨论】:

  • 严格回答标题问题:您不能重新初始化multi_array_ref(句号)。如果您想要这种行为,请使用间接。

标签: c++ multidimensional-array boost


【解决方案1】:

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

因此,您可以通过将 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的数据缓冲区。

其他想法

如果您的评论说:

从构造函数(无论是主体还是初始化器列表)内部分配缓冲区确实没有任何意义:

// 在实际应用中,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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-18
    • 1970-01-01
    • 2022-06-29
    • 2020-01-20
    • 1970-01-01
    • 2014-09-09
    相关资源
    最近更新 更多