实现高效的2d向量的正确方法是什么?我需要在2d集合中存储一组Item对象,这样可以快速迭代(最重要)并快速查找元素。
我有一个2d的指针向量声明如下:
std::vector<std::vector<Item*>> * items;
在构造函数中,我将其实例化如下:
items = new std::vector<std::vector<Item*>>();
items->resize(10, std::vector<Item*>(10, new Item()));
我如何(正确)实现访问项目的方法?例如:
items[3][4] = new Item();
AddItem(Item *& item, int x, int y)
{
items[x][y] = item;
}
我使用指针的原因是为了获得更好的性能,以便我可以通过引用传递内容。
如果有更好的方法可以解决这个问题,请解释一下,但我仍然对如何正确使用该载体感兴趣。
编辑:为了澄清,这是一个用于简单游戏中的库存管理的类的一部分。设定的10x10向量表示库存网格,其是设定大小。 Item类包含项类型,指向资源管理器中图像的指针,堆栈大小等。
我的指针用法是为了提高性能,因为这个类被迭代并用于使用图像指针每帧渲染整个库存。
答案 0 :(得分:3)
似乎你事先知道了矩阵的大小,并且这个矩阵是平方的。虽然vector<>
很好,但在这种情况下你也可以使用原生向量。
Item **m = new Item*[ n * n ];
如果你想访问位置r,c,那么你只需要将r乘以n,然后加上c:
pos = ( r * n ) + c;
因此,如果你想访问位置1,2和n = 5,那么:
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ];
此外,您可以使用智能指针,例如auto_ptr
(过时)和unique_ptr
,而不是使用普通指针,它们或多或少相似:一旦它们被销毁,它们就会破坏对象他们指着。
auto_ptr<Item> m = new auto_ptr<Item>[ n * n ];
唯一的缺点是现在需要调用get()
才能获得指针。
pos = ( 1 * 5 ) + 2;
Item * it = m[ pos ].get();
这里有一个课程总结了所有这些:
class ItemsSquaredMatrix {
public:
ItemsSquaredMatrix(unsigned int i): size( i )
{ m = new std::auto_ptr<Item>[ size * size ]; }
~ItemsSquaredMatrix()
{ delete[] m; }
Item * get(unsigned int row, unsigned int col)
{ return m[ translate( row, col ) ].get(); }
const Item * get(unsigned int row, unsigned int col) const
{ return m[ translate( row, col ) ].get(); }
void set(unsigned int row, unsigned int col, Item * it)
{ m[ translate( row, col ) ].reset( it ); }
unsigned int translate(unsigned int row, unsigned int col) const
{ return ( ( row * size ) + col ); }
private:
unsigned int size;
std::auto_ptr<Item> * m;
};
现在您只需创建课程Item
。但是如果您创建了一个特定的类,那么您必须为每个新数据复制ItemsSquaredMatrix
。在C ++中有一个特定的解决方案,涉及在模板中转换上面的类(提示:vector<>
是一个模板)。由于您是初学者,因此将Item
作为抽象类会更简单:
class Item {
public:
// more things...
virtual std::string toString() const = 0;
};
并派生您将从中创建的所有数据类。记得做演员,但是......
正如您所看到的,有很多未解决的问题,随着您不断发展,会提出更多问题。享受!
希望这有帮助。
答案 1 :(得分:2)
对于数字工作,您希望将数据尽可能本地存储在内存中。例如,如果您通过n
矩阵制作m
,则可能会将其定义为
vector<vector<double>> mat(n, vector<double>(m));
这种方法存在严重的缺点。首先,它不适用于任何适当的矩阵库,例如BLAS
和LAPACK
,它们期望数据在内存中是连续的。其次,即使它确实如此,也会导致内存中的大量随机访问和指针间接,这会破坏矩阵操作的性能。相反,您需要一个连续的内存n*m
项块。
vector<double> mat(n*m);
但你真的不想使用vector
,因为你需要手动将1d转换为2d索引。有些库在C++
中为您执行此操作。其中一个是Blitz++,但现在似乎没有太多发展。其他替代方案是Armadillo和Eigen。有关详细信息,请参阅this previous answer。
例如,使用Eigen
,矩阵声明将如下所示:
MatrixXd mat(n,m);
您可以将元素作为mat[i][j]
访问,并将矩阵乘以mat1*mat2
,依此类推。
答案 2 :(得分:1)
第一个问题是指针的原因。几乎没有任何理由
有一个指向std::vector
的指针,并不常见
你有一个指针向量。你的定义应该是:
std::vector<std::vector<Item> > items;
,或者至少(假设例如Item是a的基础) 多态层次结构):
std::vector<std::vector<Item*> > items;
至于您的问题,最好的解决方案是以某种方式包装您的数据
一个Vector2D
类,其中包含std::vector<Item>
个成员,
并进行索引计算以访问所需的元素:
class Vector2D
{
int my_rows;
int my_columns;
std::vector<Item> my_data;
public:
Vector2D( int rows, int columns )
: my_rows( rows )
, my_columns( columns )
{
}
Item& get( int row, int column )
{
assert( row >= 0 && row < my_rows
&& column >= 0 && column < my_columns );
return my_data[row * my_columns + column];
}
class RowProxy
{
Vector2D* my_owner;
int my_row;
public;
RowProxy(Vector2D& owner, int row)
: my_owner( &owner )
, my_row( row )
{
}
Item& operator[]( int column ) const
{
return my_owner->get( my_row, column );
}
};
RowProxy operator[]( int row )
{
return RowProxy( this, row );
}
// OR...
Item& operator()( int row, int column )
{
return get( row, column );
}
};
如果你放弃边界检查(但我不推荐它),那么
RowProxy
可以是一个简单的Item*
。
当然,您应该复制const
的上述内容。