是什么导致这个向量下标超出范围错误?
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;
// ...
}
}
我目前正在将一个图映射到类似扫雷的网格,其中每个块代表一个节点。
这是我的 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;
// ...
}
}