用智能指针指向vector中Station元素的C++带权有向图实现问题
问题解答
一、智能指针指向vector中Station元素的方式是否正确?
首先,当前你的实现存在两个关键问题:
智能指针类型冗余:
std::shared_ptr<Station*>是指向Station*的智能指针,完全没必要多这一层指针嵌套。我们只需要直接用std::shared_ptr<Station>来管理Station对象的生命周期即可,额外的指针层级只会增加代码复杂度和出错概率。vector元素地址失效风险:
std::vector在扩容时会重新分配内存,原有元素的地址会失效。如果直接把vector中元素的原始地址存入shared_ptr,后续vector扩容(比如添加新站点)时,这些指针会变成悬空指针,触发未定义行为。
修正方案:
- 修改
Road类的nextStation类型为std::shared_ptr<Station> - 将
TransportationSystem中的stations容器改为std::vector<std::shared_ptr<Station>>,让所有Station对象都由智能指针管理,这样即使vector扩容,智能指针的指向也不会失效。
修改后的核心类成员:
// Road类中 std::shared_ptr<Station> nextStation; // TransportationSystem类中 std::vector<std::shared_ptr<Station>> stations;
对应的节点查找逻辑也要调整为基于智能指针的匹配:
// 查找源节点的示例 auto sourceNodeIt = find_if(stations.begin(), stations.end(), [&sourceNode](const std::shared_ptr<Station>& s) { return s->getStationName() == sourceNode; });
二、完善目标节点不存在时的处理逻辑
当目标节点不存在时,我们需要先创建对应的Station对象(用智能指针管理),将其添加到stations容器中,再让当前Road的nextStation指向它,最后把Road添加到源节点的道路列表中。如果源节点也不存在,也可以按相同逻辑创建源节点。
完整处理代码:
void TransportationSystem::loadAll() { for (const auto& fileName : inputFiles) { ifstream infile(fileName); string sourceNode; string targetNode; int distance; string transportationType = getTransportationTypeByFileName(fileName); string sourceStationType; string targetStationType; while (infile >> sourceNode >> targetNode >> distance) { Road r; if (defaultValues) { r.setDefaultValues(transportationType, sourceNode, targetNode, distance); } else { r.setNonDefaultValues(transportationType, sourceNode, targetNode, distance, getTransitionTimeByTransportationType(transportationType)); } // 获取源和目标站点的类型 sourceStationType = getStationTypeBySourceNode(sourceNode); targetStationType = getStationTypeBySourceNode(targetNode); // 查找源节点 auto sourceNodeIt = find_if(stations.begin(), stations.end(), [&sourceNode](const std::shared_ptr<Station>& s) { return s->getStationName() == sourceNode; }); // 查找目标节点 auto targetNodeIt = find_if(stations.begin(), stations.end(), [&targetNode](const std::shared_ptr<Station>& s) { return s->getStationName() == targetNode; }); std::shared_ptr<Station> sourceStation; // 处理源节点不存在的情况 if (sourceNodeIt == stations.end()) { int sourceWaitingTime = getWaitingTimeByStationType(sourceStationType); sourceStation = std::make_shared<Station>(sourceNode, sourceStationType, sourceWaitingTime); stations.push_back(sourceStation); } else { sourceStation = *sourceNodeIt; } std::shared_ptr<Station> targetStation; // 处理目标节点不存在的情况 if (targetNodeIt == stations.end()) { int targetWaitingTime = getWaitingTimeByStationType(targetStationType); targetStation = std::make_shared<Station>(targetNode, targetStationType, targetWaitingTime); stations.push_back(targetStation); } else { targetStation = *targetNodeIt; } // 绑定Road的目标站点并添加到源站点的道路列表 r.nextStation = targetStation; sourceStation->addRoad(r); } } }
额外注意事项:
- 建议用
find_if替代find来匹配节点,避免依赖Station::operator==的具体实现(如果原operator==不是仅按站点名称比较,会导致匹配错误)。 - 如果业务需求中不允许自动创建不存在的站点,可以在节点不存在时抛出
CouldNotOpenFileException或自定义异常,跳过当前道路的加载。
内容的提问来源于stack exchange,提问作者Amir Baum
相关产品推荐
相关产品推荐

