c ++非指针向量

时间:2014-12-23 03:33:19

标签: c++ pointers vector smart-pointers

我的TileMap班级有std::vector<Tile>。在生成向量时,我注意到Tile在创建后不久就被删除了,因此不允许TileMap类对它们做任何事情。

TileMap是一种信息类,Stage类将用于各种事物,因此需要访问TileMap.tiles()(返回mTiles_ TileMap

TileMap构造函数:

TileMap::TileMap(std::vector<int> pTiles, int pWidth):mWidth_(pWidth)
{
    for(int i = 0; i < pTiles.size(); i++)
    {
        int x = (i % mWidth_);
        int y = floorf(i / mWidth_);
        Tile tile((Tile::TileType)pTiles[i]);
        tile.x = x;
        tile.y = y;
        tile.position(sf::Vector2f(x * Tile::TILE_WIDTH, y * Tile::TILE_HEIGHT));
        mTiles_.push_back(tile);
    }
}

之前它是std::vector<std::shared_ptr<Tile>>,但我看到我是否可以使用指针。有没有办法做到这一点?

编辑:添加了平铺定义 -

class Tile : public SquareCollidableObject
{
public:

    enum TileType {
        TILE_GRASS,
        TILE_OUTSIDE_WALL_TOP_LEFT_OUTER,
        TILE_OUTSIDE_WALL_TOP,
        TILE_OUTSIDE_WALL_TOP_RIGHT_OUTER,
        TILE_OUTSIDE_WALL_LEFT,
        TILE_OUTSIDE_WALL_RIGHT,
        TILE_OUTSIDE_WALL_BOTTOM_RIGHT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_LEFT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_LEFT_OUTER,
        TILE_OUTSIDE_WALL_BOTTOM,
        TILE_OUTSIDE_WALL_TOP_RIGHT_INNER,
        TILE_OUTSIDE_WALL_TOP_LEFT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_RIGHT_OUTER,
        TILE_WALL,
        TILE_INSIDE_WALL_TOP_LEFT_INNER,
        TILE_INSIDE_WALL_TOP,
        TILE_INSIDE_WALL_TOP_RIGHT_INNER,
        TILE_INSIDE_WALL_LEFT,
        TILE_INSIDE_WALL_RIGHT,
        TILE_INSIDE_WALL_BOTTOM_RIGHT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_LEFT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_LEFT_INNER,
        TILE_INSIDE_WALL_BOTTOM,
        TILE_INSIDE_WALL_TOP_RIGHT_OUTER,
        TILE_INSIDE_WALL_TOP_LEFT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_RIGHT_INNER,
        TILE_FLOOR
    };

    Tile(TileType);
    virtual ~Tile();

    virtual void update(float);
    virtual void draw(sf::RenderWindow&, sf::Vector2f);

    TileType tileType;

    static int TILE_WIDTH;
    static int TILE_HEIGHT;

    int x;
    int y;

    // pathfinding
    std::shared_ptr<Tile> previousTile;
    float g; // cost to tile (total cost from previous tiles + cost to this tile)
    float h; // cost to next tile
    float f; // g + h
    bool walkable;
};

3 个答案:

答案 0 :(得分:1)

Tile需要一个复制(或移动)构造函数和赋值运算符,以便与std::vector一起使用。 nTiles_.push_back(tile)从本地Tile复制构建新的tile对象。

在for循环中,在每次迭代时,构造本地对象tile,然后将副本推入向量,然后本地tile被破坏。这就是在for循环期间调用析构函数的原因。

一种避免这种情况的方法,而只构建Tile中的vector对象,你可以编写

TileMap::TileMap(std::vector<int> pTiles, int pWidth):mWidth_(pWidth)
{
    for(int i = 0; i < pTiles.size(); i++)
    {
        int x = (i % mWidth_);
        int y = floorf(i / mWidth_);

        mTiles_.emplace_back( (Tile::TileType)pTiles[i] );
        Tile& tile = mTiles_.back();
        tile.x = x;
        tile.y = y;
        tile.position(sf::Vector2f(x * Tile::TILE_WIDTH, y * Tile::TILE_HEIGHT));
    }
}

emplace_back获取Tile构造函数的参数,并在vector的末尾就地构造一个对象。 back返回对最后一项的引用。

如果Tile对象是重量级的(即复制它们很昂贵),最好像以前一样使用指针,或者实现move-constructor和move-assignment运算符。如果插入/删除新项目,或者向量调整大小,std::vector将复制(或移动)其项目。

tiles()函数还需要通过引用返回vector

答案 1 :(得分:1)

您的代码中有两个破坏瓦片的原因:

您在向量内复制的局部变量,以及向量调整内部内存大小时的内部副本。

为了避免前者,你必须放回新元素;对于后者,你必须在矢量中保留位置。结果如下:

TileMap::TileMap(const std::vector<int>& pTiles, int pWidth) : mWidth_(pWidth)
{
    mTiles_.reserve(pTiles.size());
    for(int i = 0; i != pTiles.size(); ++i)
    {
        const int x = i % mWidth_;
        const int y = i / mWidth_;
        mTiles_.emplace_back(static_cast<Tile::TileType>(pTiles[i]));
        Tile& tile = mTiles_.back();
        tile.x = x;
        tile.y = y;
        tile.position(sf::Vector2f(x * Tile::TILE_WIDTH, y * Tile::TILE_HEIGHT));
    }
}

答案 2 :(得分:0)

首先,你的TileMap构造函数调用.position,它不是Tile类的成员。

其次,@ tmlen的回答看起来像我预期的那样有效。如果我运行此代码:

#include <stdlib.h>
#include <memory>
#include <vector>
#include <iostream>

using namespace std;

class Tile
{
public:

    enum TileType {
        TILE_GRASS,
        TILE_OUTSIDE_WALL_TOP_LEFT_OUTER,
        TILE_OUTSIDE_WALL_TOP,
        TILE_OUTSIDE_WALL_TOP_RIGHT_OUTER,
        TILE_OUTSIDE_WALL_LEFT,
        TILE_OUTSIDE_WALL_RIGHT,
        TILE_OUTSIDE_WALL_BOTTOM_RIGHT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_LEFT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_LEFT_OUTER,
        TILE_OUTSIDE_WALL_BOTTOM,
        TILE_OUTSIDE_WALL_TOP_RIGHT_INNER,
        TILE_OUTSIDE_WALL_TOP_LEFT_INNER,
        TILE_OUTSIDE_WALL_BOTTOM_RIGHT_OUTER,
        TILE_WALL,
        TILE_INSIDE_WALL_TOP_LEFT_INNER,
        TILE_INSIDE_WALL_TOP,
        TILE_INSIDE_WALL_TOP_RIGHT_INNER,
        TILE_INSIDE_WALL_LEFT,
        TILE_INSIDE_WALL_RIGHT,
        TILE_INSIDE_WALL_BOTTOM_RIGHT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_LEFT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_LEFT_INNER,
        TILE_INSIDE_WALL_BOTTOM,
        TILE_INSIDE_WALL_TOP_RIGHT_OUTER,
        TILE_INSIDE_WALL_TOP_LEFT_OUTER,
        TILE_INSIDE_WALL_BOTTOM_RIGHT_INNER,
        TILE_FLOOR
    };

    Tile(TileType t):
        tileType(t)
    {
        cout << "Constructing tile\n";
    }

    virtual ~Tile()
    {
        cout << "Destructing tile\n";
    }


    TileType tileType;

    static int TILE_WIDTH;
    static int TILE_HEIGHT;

    int x;
    int y;

    // pathfinding
    std::shared_ptr<Tile> previousTile;
    float g; // cost to tile (total cost from previous tiles + cost to this tile)
    float h; // cost to next tile
    float f; // g + h
    bool walkable;
};

class TileMap
{
    int mWidth_;
    std::vector<Tile> mTiles_;

    public:
        TileMap(const std::vector<int>& pTiles, int pWidth) : mWidth_(pWidth)
        {
            mTiles_.reserve(pTiles.size());
            for (int i = 0; i != pTiles.size(); ++i)
            {
                const int x = i % mWidth_;
                const int y = i / mWidth_;
                mTiles_.emplace_back(static_cast<Tile::TileType>(pTiles[i]));
                Tile& tile = mTiles_.back();
                tile.x = x;
                tile.y = y;
                //tile.position(sf::Vector2f(x * Tile::TILE_WIDTH, y * Tile::TILE_HEIGHT));
            }
        }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<int> tiles;
    tiles.push_back(Tile::TileType::TILE_GRASS);
    cout << "Creating tilemap\n";
    TileMap t(tiles, tiles.size());
    cout << "Tilemap created\n";
    cout << "Exiting\n";
    return 0;
}

我得到以下结果:

Creating tilemap
Constructing tile
Tilemap created
Exiting
Destructing tile