Попытка сослаться на удаленную функцию с вектором unique_ptr - PullRequest
1 голос
/ 16 января 2020

Я пытаюсь сделать текстовую монопольную игру. Для каждой плитки на доске у меня есть объект Tile или PropertyTile. PropertyTile является дочерним элементом класса Tile с дополнительными свойствами. Первоначально у меня был вектор для хранения всех плиток, как Tile, так и PropertyTile, но позже выяснилось, что из-за нарезки объектов правильным будет использовать unique_ptr.

Когда я переключился на unique_ptr, я получил 2 из той же ошибки:

Error   C2280    'std::unique_ptr<Tile,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
    with
    [
        _Ty=Tile
    ]   MonopolyFinal   C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.22.27905\include\xutility    1768    

Первая проблема была решена путем помещения move () в Map :: getAllTiles (), как показано ниже. Вторая ошибка указывает на строку 30 Map.h, которая (vector<unique_ptr<Tile>> tiles;).

Для Map. cpp Map :: Map (), я пробовал и emplace_back и push_back, с и без move ().

Я не уверен, что делаю не так. Весь соответствующий код ниже. Заранее спасибо.

Map.h:

    class Map
{
    public:

        Map();

        void display(Player, Player, Player, Player);

        vector<unique_ptr<Tile>> getAllTiles();

        vector<vector<bool>> getAllTileValidty();

    private:
        vector<unique_ptr<Tile>> tiles;
        vector<vector<bool>> tileValidity;
    };

Конструктор в Map. cpp, который заполняет вектор плиток:

Map::tiles.push_back(move(unique_ptr<Tile>(new PropertyTile("Mediterranean Ave", 9, 10, "Brown", 60, 2, 50) )));
Map::tiles.push_back(move(unique_ptr<Tile>(new Tile("Community Chest", 8, 10)))); //Community Chest (usually gives you extra money) 

Получатель для плиток вектор:

    vector<unique_ptr<Tile>> Map::getAllTiles()
{
    return move(tiles);
}

1 Ответ

0 голосов
/ 17 января 2020

* * * root ваших проблем в том, что std::unique_ptr не может быть скопировано, только перемещено. Он не может быть скопирован, так как только один unique_ptr может владеть объектом. Все ваши ошибки связаны с тем, что вы пытаетесь скопировать такие unique_ptr объекты, несмотря на это. Конечно, вы можете заменить std::unique_ptr на std::shared_ptr, но тогда один и тот же объект будет использоваться несколькими объектами Map. Измените заостренный объект от одного Map, и это повлияет на другой. Не уверен, что вы этого хотите.

Скорее всего, ваше решение о движении неверно:

std::vector<std::unique_ptr<Tile>> Map::getAllTiles()
{
    return move(tiles);
}

Это уничтожит tiles в объекте Map. Либо имя функции неверно, либо это не то, что вам нужно. Вероятным решением будет использование clone()

std::vector<std::unique_ptr<Tile>> Map::getAllTiles()
{
    std::vector<std::unique_ptr<Tile>> result;
    result.reserve(tiles.size());
    for (const auto & tile_ptr: tiles) 
    {
        result.push_back(tile_ptr->clone());
    }  
    return result; // OK, a local is automatically moved, possibly elided 
}

Где Tile и все его потомки реализуют клон:

class Tile {
  ...
  virtual std::unique_ptr<Tile> clone() const 
  { 
     return std::make_unique<Tile>(*this);
  }
  ..
};
class PropertyTile : public Tile {
  ...
  std::unique_ptr<Tile> clone() const override
  { 
     return std::make_unique<PropertyTile>(*this);
  }
  ..
};

Что касается ошибки в строке 30 Map.h , (vector<unique_ptr<Tile>> tiles;), я подозреваю, что это из-за автоматически сгенерированного конструктора копирования. Либо удалите копию и присваивание:

class Map {
 public:
    Map(const Map&) = delete;
    Map& operator=(const Map&) = delete;

Либо так, либо реализуйте их правильно, клонируя все элементы вектора, по одному.

Кроме того, даже если не root Что касается вашей проблемы, следующее далеко не лучшая практика:

push_back(move(unique_ptr<Tile>(new PropertyTile(....

Лучше использовать std::make_unique, который доступен с C ++ 14:

push_back(std::make_unique<PropertyTile>("Mediterranean Ave", 9, 10,....

Наконец, никогда не пишите using namespace std в любом месте вашего кода, а также using std::vector в заголовочном файле. Оба неверны:

  • using namespace std - это ночной кошмар для обеспечения совместимости кода с более поздней версией для новых версий стандарта C ++.
  • using std::vector - это кошмар для пользователей Map.h, который может захотеть использовать другой заголовочный файл с другим типом вектора, например using std::pmr::vector. Они будут друг с другом sh
...