c++ - 尝试使用unique_ptr的 vector 引用已删除的函数

标签 c++ vector polymorphism unique-ptr

我正在尝试制作基于文本的大富翁游戏。对于板上的每个磁贴,我都有一个Tile或PropertyTile对象。 PropertyTile是Tile类的子级,具有其他属性。
最初,我有一个 vector 来容纳所有图块,包括Tile和PropertyTile,但后来发现由于对象 slice ,正确的方法是使用unique_ptr。

当我切换到unique_ptr时,我遇到了两个相同的错误:

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()中来解决第一个问题,如下所示。
第二个错误指​​向Map.h的第30行,即(vector<unique_ptr<Tile>> tiles;)。

对于Map.cpp Map::Map(),无论是否使用move(),我都尝试了emplace_back和push_back。

我不确定自己在做什么错。以下所有相关代码。提前致谢。

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中的构造函数,用于填充图块 vector :
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 的 setter/getter :
    vector<unique_ptr<Tile>> Map::getAllTiles()
{
    return move(tiles);
}

最佳答案

问题的根源是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);
  }
  ..
};

至于Map.h第30行的错误,即(vector<unique_ptr<Tile>> tiles;),我怀疑这是由于自动生成的副本构造函数造成的。删除副本和分配:
class Map {
 public:
    Map(const Map&) = delete;
    Map& operator=(const Map&) = delete;

要么,要么通过克隆载体的所有元素一个接一个地正确实现它们。

此外,即使不是问题的根源,以下操作也不是最佳实践:
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::vectorMap.h用户的噩梦,他们可能希望使用具有不同 vector 类型的其他头文件,例如using std::pmr::vector。这些将相互冲突。
  • 关于c++ - 尝试使用unique_ptr的 vector 引用已删除的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59762763/

    相关文章:

    c++ - 将元素插入左倾的黑红树c++

    c++ - std::set 的 union 操作

    arrays - 在 AS3 中使用值数组初始化 Vector 是否会部分违背 Vector 的目的?

    c++ - 在 C++ 中从 Vector 中删除一个元素

    c++ - 覆盖基类无法正常工作

    python - 根据传递给构造函数的参数实现Python类

    c++ - 使用类时如何使用链表

    c++ - append 两个字符时出现段错误 - C++

    c++ - 如何正确地从 vector 的一部分中找到一个值?

    java - Java中的动态多态性有什么好处?