【问题标题】:What causes this vector subscript out of range Error?是什么导致这个向量下标超出范围错误?
【发布时间】:2021-12-13 17:49:49
【问题描述】:

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

    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);
        }
    }

我在另一个类的某个地方读取鼠标坐标并将它们转换为“图形坐标”:

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 错误,这有点奇怪,有人可以向我解释我做错了什么。当我尝试将鼠标悬停在交互区域的“边界”之外时,总是会显示此错误,稍微位于第一个或最后一个节点的后面或前面。

提前致谢。

【问题讨论】:

  • 使用调试器应该很容易找到(Linux 上的 GDB,Windows 上的 VS)。它是否向您显示了它发生的代码行?
  • @pptaszni,很遗憾没有。
  • 如果 numNodesWidth 恰好用 bounds.x / nodeSize.x 初始化,如果除法有余数,则舍入可能会导致类似的问题。默认情况下,值向零舍入。
  • 认为规模转换正在做的事情与实际发生的事情不同。调试是为了消除差异。如何做到这一点本身就是一个编程问题。常见的方法是通过仔细阅读代码、添加日志记录和使用调试器进行逻辑推理。要求其他人在 SO 中执行其中一个(这里只有第一个是可能的,因为您提供了不完整的信息)是另一种选择。但这并不是一件好事,因为您错过了提高自己技能的机会。
  • @aa 不知怎的,我得到的向量下标超出了 1655 的范围——如果你写了代码,就没有“不知何故”。你有一个计划,你编写了计划,现在你的程序中的某些东西与你的计划背道而驰。您的工作是调试程序以查看代码与您的计划的差异。运行时基本上为您提供调试问题所需的所有信息,即向量下标超出范围。

标签: c++ matrix vector coordinates sfml


【解决方案1】:

不保证bounds &lt;= 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&lt;uint32_t&gt;(mouseCoord.x / nodeSize.x)} 肯定会返回不大于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;
    // ...
  }
}

【讨论】:

    猜你喜欢
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多