为什么我的程序说无序映射中的内存位置超出范围?

问题描述 投票:0回答:1

我目前正在用 C++ 编写一个控制台程序,该程序构建使用无序映射相互连接的节点和弧的网络/图。该应用程序的目的是演示处理命令和从网络/图形检索信息的“最有效”方式。我已附上[类似示例的图表]。(https://i.sstatic.net/51FY0RHO.png)。

下面是我的

BuildNetwork()
文件中的
Network.cpp
方法以及我的
Graph.cpp
Node.cpp
Arc.cpp
类,以便您可以了解我的网络是如何构建的:

bool Navigation::BuildNetwork(const std::string& fileNamePlaces, const std::string& fileNameLinks)
{
    std::ifstream finPlaces(fileNamePlaces), finLinks(fileNameLinks);
    if (!finPlaces || !finLinks)
        return false;

    std::string line;
    // Parse Places
    while (getline(finPlaces, line)) {
        std::istringstream iss(line);
        std::string name, idStr, latitudeStr, longitudeStr;
        if (getline(iss, name, ',') && getline(iss, idStr, ',') && getline(iss, latitudeStr, ',') && getline(iss, longitudeStr)) {
            int id = std::stoi(idStr);
            double latitude = std::stod(latitudeStr), longitude = std::stod(longitudeStr);
            Node node(id, name, latitude, longitude);
            networkGraph.addNode(node);
        }
    }

    // Parse Links
    while (getline(finLinks, line)) {
        std::istringstream iss(line);
        std::string startIdStr, endIdStr, modeStr;
        if (getline(iss, startIdStr, ',') && getline(iss, endIdStr, ',') && getline(iss, modeStr)) {
            int startNodeId = std::stoi(startIdStr), endNodeId = std::stoi(endIdStr);
            TransportMode mode = parseTransportMode(modeStr);
            Arc arc(startNodeId, endNodeId, mode);
            networkGraph.addArc(startNodeId, arc);
        }
    }

    return true;
}

// Helper function to parse string to TransportMode
TransportMode Navigation::parseTransportMode(const std::string& modeStr) {
    static const std::unordered_map<std::string, TransportMode> modeMap = {
        {"Ship", TransportMode::Ship}, {"Rail", TransportMode::Rail},
        {"Bus", TransportMode::Bus}, {"Car", TransportMode::Car},
        {"Bike", TransportMode::Bike}, {"Foot", TransportMode::Foot}
    };
    auto it = modeMap.find(modeStr);
    if (it != modeMap.end())
        return it->second;
    return TransportMode::Foot;  // Default or error case
}
#include "Graph.h"

Graph::Graph() {}
Graph::~Graph() {}

void Graph::addNode(const Node& node) {
    nodes[node.getId()] = node;
}

void Graph::addArc(int startNodeID, const Arc& arc) {
    if (nodeExists(startNodeID) && nodeExists(arc.getEndNodeID())) {
        if (adjacencyList.find(startNodeID) == adjacencyList.end()) {
            adjacencyList[startNodeID] = std::vector<Arc>(); // Initialize if not already
        }
        adjacencyList[startNodeID].push_back(arc);
    }
}

Node& Graph::getNode(int nodeId) {
    return nodes.at(nodeId);
}

const Node& Graph::getNode(int nodeId) const {
    return nodes.at(nodeId);
}

const std::vector<Arc>& Graph::getArcs(int nodeId) const {
    return adjacencyList.at(nodeId);
}

bool Graph::nodeExists(int nodeId) const {
    return nodes.find(nodeId) != nodes.end();
}

bool Graph::arcExists(int startNodeID, int endNodeID) const {
    auto it = adjacencyList.find(startNodeID);
    if (it != adjacencyList.end()) {
        return std::any_of(it->second.begin(), it->second.end(), [endNodeID](const Arc& arc) {
            return arc.getEndNodeID() == endNodeID;
            });
    }
    return false;
}

const std::unordered_map<int, Node> Graph::getAllNodes() const {
    return nodes;
}
#include "Node.h"

Node::Node(int id, const std::string& name, double latitude, double longitude)
    : id(id), name(name)
{
    Utility::LLtoUTM(latitude, longitude, y, x);
}

//Setting "getters" as const as they're not changing once set
int Node::getId() const 
{
    return id;
}
std::string Node::getName() const 
{
    return name;
}
double Node::getX() const 
{
    return x;
}
double Node::getY() const 
{
    return y;
}
#include "Arc.h"

Arc::Arc(int startNodeID, int endNodeID, TransportMode transportMode, double distance)
    : startNodeID(startNodeID), endNodeID(endNodeID), transportMode(transportMode), distance(distance) {}

int Arc::getStartNodeID() const {
    return startNodeID;
}

int Arc::getEndNodeID() const {
    return endNodeID;
}

TransportMode Arc::getTransportMode() const {
    return transportMode;
}

double Arc::getDistance() const {
    return distance;
}

void Arc::setDistance(double dist) {
    distance = dist;
}

如您所见,它利用无序映射来存储节点和弧。我已经实现了一种计算

Network.cpp
中两个节点之间最远距离的方法。请记住,这可以完美地工作:

bool Navigation::maxDist(const std::string& params) {
    double maxDistance = 0.0;
    std::string farthestNodes;
    const auto& nodes = networkGraph.getAllNodes(); // Ensure this returns a reference to the map

    for (auto it1 = nodes.begin(); it1 != nodes.end(); ++it1) {
        for (auto it2 = std::next(it1); it2 != nodes.end(); ++it2) {
            // Calculate Euclidean distance between nodes in meters, then convert to kilometers
            double dx = it2->second.getX() - it1->second.getX();
            double dy = it2->second.getY() - it1->second.getY();
            double squaredDistance = dx * dx + dy * dy;

            if (squaredDistance > maxDistance) {
                maxDistance = squaredDistance;
                farthestNodes = it1->second.getName() + " to " + it2->second.getName();
            }
        }
    }
    maxDistance = sqrt(maxDistance) / 1000.0; // Convert from meters to kilometers
    std::cout << "Max Distance: " << maxDistance << " km between " << farthestNodes << std::endl;
    return true;
}

然而,问题是当我尝试实现一种方法来计算哪个节点具有最多的连接弧时:

bool Navigation::maxLink(const std::string& params)
{
    double maxDistance = 0.0;
    std::string longestLinkDescription;
    Node startNode, endNode;

    // Iterate over all nodes to access their adjacency lists
    for (const auto& nodePair : networkGraph.getAllNodes()) {
        int nodeId = nodePair.first;
        const auto& arcs = networkGraph.getArcs(nodeId);

        // Check each arc for this node
        for (const auto& arc : arcs) {
            // Make sure the end node exists to avoid out of bounds
            if (!networkGraph.nodeExists(arc.getEndNodeID())) {
                continue; // Skip this arc if the end node doesn't exist
            }

            Node start = networkGraph.getNode(nodeId);
            Node end = networkGraph.getNode(arc.getEndNodeID());

            // Calculate distance using the coordinates stored in nodes
            double distance = Utility::arcLength(start.getY(), start.getX(), end.getY(), end.getX());

            // Check if this is the longest arc found so far
            if (distance > maxDistance) {
                maxDistance = distance;
                startNode = start;
                endNode = end;
                longestLinkDescription = start.getName() + " to " + end.getName();
            }
        }
    }

    // Output the longest link found and its distance
    if (longestLinkDescription.empty()) {
        std::cout << "No valid links found." << std::endl;
        return false;
    }
    else {
        std::cout << "Longest Link: " << longestLinkDescription << " - " << std::fixed << std::setprecision(3) << maxDistance << " km" << std::endl;
        return true;
    }
}

当我编译并运行程序时,出现以下错误:

Unhandled exception at 0x00007FF924A2AB89 in Network.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0000008FF973E380.

这让我很困惑,因为我已经测试过,每个节点和弧都是通过程序早期的调试构建和初始化的,所以肯定不应该有任何超出范围的内存位置。这让我认为这不是网络构建本身的问题,而是该方法在无序映射中运行的方式的问题。由于它没有具体告诉我出了什么问题,我真的不确定如何解决这个问题。我对使用无序映射相对缺乏经验,但有人告诉我这是建立这样的网络的有效方法。如何解决我看到的错误?

c++ unordered-map
1个回答
0
投票

我很确定问题是由于我的

GetArcs()
中的
Grid.cpp
方法不接受没有附加弧的节点。我已更新该方法以仅返回空列表/弧向量。现在运行完美。

const std::vector<Arc>& Graph::getArcs(int nodeId) const {
static const std::vector<Arc> emptyArcList;
auto it = adjacencyList.find(nodeId);
if (it != adjacencyList.end()) {
    return it->second;
}
else {
    return emptyArcList;
}
© www.soinside.com 2019 - 2024. All rights reserved.