我的情况类似于以下
struct Cell
{
uint16_t x, y;
// other fields
Cell* right();
Cell* above();
...
}
class Container
{
private:
uint16_t width, height;
Cell* data;
public:
Container(uint16_t width, uint16_t height) :
width(width), height(height), data(new Cell[width*height]) { }
Cell* cellAt(uint16_t x, uint16_t y) { &data[x*height + y]; }
};
Container* container;
Cell* Cell::right() { return container->cellAt(x+1, y); }
...
为了显示设计,我修剪了大部分代码(例如范围检查等等)。
基本上,这允许我在代码中的任何地方访问相邻单元而不直接传递Container对象(这将产生更多冗长的代码,并且邻居在代码库周围访问数百次)。该解决方案运行良好,甚至不需要在代码周围知道Container
类,因为Cell
就足够了。
这种方法有一个很大的限制:它只允许Container
的一个实例。现在我发现自己处于需要Container
的多个实例的情况,具有独立的Cell
数组,但我不想更改代码的结构。
我正在考虑一种允许多个Container
但是
Container*
内存储Cell
以避免浪费大量内存(我们谈论的是数百万个单元格)我在考虑分配width*height + 1
Cell
个实例并使用第一个实例在其内存中存储Container*
,但问题是如何计算第一个Cell的地址总宽度/高度是Container
本身的字段(Cell
不知道)。
所以我想我应该为每列存储至少一个指向Container*
的指针(它们按cellAt
函数显示的列存储,其次要原因对问题无用)。这会浪费每个height*sizeof(Cell)
的{{1}}字节,这可能相当多,但我猜单指针是没办法的。
基本上我可以做类似的事情:
Container
然后检索对象。当然,这是一个肮脏的黑客行为,可能会给架构带来问题,如果Container** container = reinterpret_cast<Container**>(&data[0]);
*container = this;
不支持未对齐的访问。
我是否缺少更智能的解决方案?
答案 0 :(得分:1)
我有3个解决方案。
细胞知道它们位于连续的2d缓冲区中。
在较低维度中查找第一个元素很容易。所以现在你在(N,0)
。如果N
为0
,我们就完成了,我们找到了2d数组的开头。
之前的元素是(N-1,Last)
,其中Last+1
是较低维度的大小。现在您可以跳转到(0,0)
。
或者,从单元格中删除x和y,替换为容器指针。从this
和容器指针的地址动态计算x和y。
如果我们想要认真对待,我们会删除所有多余的信息。
杀死x和y。写一个存储Cell*
和Container*
的单元格视图类型。通过此视图调解与Cell
的所有互动。它计算x
和y
并知道容器大小。它只能将Container*
指针传递给Cell
的每个方法。
CellView
然后替换代码库中的Cell*
。您甚至可以覆盖->
以返回this
并保持大部分用途不变。
CellView cellAt(uint16_t x, uint16_t y) { return {&data[x*height + y], this}; }
struct Cell{
// uint16_t x, y;
// other fields
Cell* right(Container*);
Cell* above(Container*);
...
};
struct CellView{
// maybe: uint16_t x, y;
Cell* cell;
Container* container;
CellView right()const{ return {cell->right(container), container}; };
CellView above()const{ return {cell->above(container), container}; };
...
};
基本上将状态移动到“指针”并移出单元格。
答案 1 :(得分:0)
考虑到您所说的限制,以下是两种可能的解决方案:
1)对于需要Container完成工作的所有函数,只需要将Container作为参数。
例如:
Cell* Cell::right(Container* container)
{
return container->cellAt(x+1, y);
}
2)不要询问Cell有关Container知道的事情,而是向Container询问其Cell。换句话说,将right
,above
和类似函数移动到Container。
例如:
Cell* Container::nextRightCell(Cell* from)
{
return cellAt(from->x+1, from->y);
}
答案 2 :(得分:0)
使用全局Container
数组并使用Cell
和Container
上的多态来获得模板整数参数,以存储Container
的索引...
我不认为这是一个好主意(Cell
成为一个纯粹的虚拟抽象结构)但是,只是为了好玩...
#include <cstdint>
#include <iostream>
struct Cell
{
uint16_t x, y;
// other fields
virtual Cell* right() = 0;
//Cell* above();
};
class Container
{
private:
uint16_t width, height;
Cell* data;
public:
Container(uint16_t w0, uint16_t h0, Cell * d0)
: width(w0), height(h0), data(d0)
{ }
Cell* cellAt(uint16_t x, uint16_t y)
{ return &data[x*height + y]; }
};
Container * containers[10];
template <std::size_t I>
struct CellI : public Cell
{
Cell* right()
{ std::cout << I << std::endl; return containers[I]->cellAt(x+1, y); }
};
template <std::size_t I>
class ContainerI : public Container
{
public:
ContainerI (uint16_t w0, uint16_t h0)
: Container(w0, h0, new CellI<I>[w0*h0])
{ }
};
int main()
{
containers[0] = new ContainerI<0>(10, 20);
containers[1] = new ContainerI<1>(20, 40);
containers[2] = new ContainerI<2>(30, 60);
// ...
containers[0]->cellAt(5,5)->right(); // print 0
containers[1]->cellAt(5,5)->right(); // print 1
containers[2]->cellAt(5,5)->right(); // print 2
}