如何使用指针的2d向量

时间:2012-11-05 17:45:31

标签: c++ pointers stl vector

实现高效的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类包含项类型,指向资源管理器中图像的指针,堆栈大小等。

我的指针用法是为了提高性能,因为这个类被迭代并用于使用图像指针每帧渲染整个库存。

3 个答案:

答案 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));

这种方法存在严重的缺点。首先,它不适用于任何适当的矩阵库,例如BLASLAPACK,它们期望数据在内存中是连续的。其次,即使它确实如此,也会导致内存中的大量随机访问和指针间接,这会破坏矩阵操作的性能。相反,您需要一个连续的内存n*m项块。

vector<double> mat(n*m);

但你真的不想使用vector,因为你需要手动将1d转换为2d索引。有些库在C++中为您执行此操作。其中一个是Blitz++,但现在似乎没有太多发展。其他替代方案是ArmadilloEigen。有关详细信息,请参阅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的上述内容。

相关问题