是什么导致这个向量下标超出范围错误?

What causes this vector subscript out of range Error?

我目前正在将一个图映射到类似扫雷的网格,其中每个块代表一个节点。 这是我的 Graph class:

    class Graph : public sf::Drawable
    {
        public:
            Graph(uint32_t numNodesWidth, uint32_t numNodesHeight);

            [[nodiscard]] std::vector<Node> & operator[](std::size_t i) 
            { return data[i]; }


            [[nodiscard]] sf::Vector2u dimension() const 
            { return {static_cast<uint32_t>(data.size()), 
              static_cast<uint32_t>(data[0].size())};}
            ...
            ...
        private:
            std::vector<std::vector<Node>> data;
    };

这里是构造函数的实现:

    Graph::Graph(uint32_t numNodesWidth, uint32_t numNodesHeight)
    {
        data.resize(numNodesHeight);
        for(auto & row : data)
        {
            row.resize(numNodesWidth);
        }
    }

在另一个地方 class 我读取了鼠标坐标并将其转换为“图形坐标”:

sf::Vector2u translatedCoords = toGraphCoords(sf::Mouse::getPosition(window), nodeSize_);
bool inBounds = checkGraphBounds(translatedCoords, graph.dimension());

以下是辅助函数:

        sf::Vector2u toGraphCoords(sf::Vector2i mouseCoord, sf::Vector2f nodeSize)
        {
            return {static_cast<uint32_t>(mouseCoord.y / nodeSize.y), 
                    static_cast<uint32_t>(mouseCoord.x / nodeSize.x)};
        }

        bool checkGraphBounds(sf::Vector2u mouseCoord, sf::Vector2u bounds)
        {
            return mouseCoord.x >= 0 && 
                    mouseCoord.y >= 0 && 
                    mouseCoord.x < bounds.x && 
                    mouseCoord.y < bounds.y ;
        }

不知何故,当我尝试使用这些新检查的坐标时出现 vector subscript out of range 1655 错误,这有点奇怪,有人可以向我解释我做错了什么。当我尝试将鼠标悬停在交互区域的“边界”之外,即第一个或最后一个节点稍稍靠后或靠前时,总是会出现此错误。

提前致谢。

不保证bounds <= num_nodes * node_size。这是特别危险的,因为涉及整数除法,这意味着您将受到四舍五入的支配。

可以 打乱代码直到出现这样的保证,但还有更好的方法。

如果 checkGraphBounds() 函数在与网格相同的数学运算上运行,您可以确定结果将与网格一致,无论它与边界的关系如何。

这样做的理想方法是实际使用 toGraphCoords() 作为其中的一部分:

bool checkGraphBounds(sf::Vector2u mouseCoord, const Graph& graph, 
                      sf::Vector2f nodeSize)
{
    auto coord = toGraphCoords(mouseCoord, nodeSize);

    return coord.x >= 0 && 
           coord.y >= 0 && 
           coord.x < graph.dimensions().x && 
           coord.y < graph.dimensions().y) ;
}

有了这个,您可以正式保证如果 mouseCoord 通过该测试,static_cast<uint32_t>(mouseCoord.x / nodeSize.x)} 肯定会 return 不大于 graph.dimensions().x 的值。

就我个人而言,我会将这两个函数组合为 Graph 的方法,如下所示:

class Graph : public sf::Drawable {
    // Make nodeSize a member of the Graph
    sf::Vector2f nodeSize_; 

    // This is one of the cases where caching an inferable value is worth it.
    sf::Vector2u dimensions_; 

  public:
    std::optional<sf::Vector2u> toGraphCoords(sf::Vector2i mouseCoord) {
      sf::Vector2u coord{
        static_cast<uint32_t>(mouseCoord.y / nodeSize_.y), 
        static_cast<uint32_t>(mouseCoord.x / nodeSize_.x)};
      };

      // No need to compare against 0, we are dealing with unsigned ints
      if(coord.x < dimensions_.x &&
         coord.y < dimensions_.y ) {
        return coord;
      }
      return std::nullopt;
    }

    // ...
};

用法:

void on_click(sf::Vector2i mouse_loc) {
  auto maybe_graph_coord = the_graph.toGraphCoords(mouse_loc);

  if(maybe_graph_coord) {
    sf::Vector2u graph_coord = *maybe_graph_coord;
    // ...
  }
}