C++中删除multiset内指定tm元素时出现错误的技术咨询
解决思路与完整实现
首先得指出几个核心问题,这是你代码能正常工作的前提:
- 你的
DeleteTrain方法带了const修饰,但删除容器元素会修改m_oTrainGraphic,所以必须去掉这个const; multiset删除元素后当前迭代器会失效,得用erase返回的迭代器来继续遍历;tm结构体的默认逐成员比较可能不符合预期(比如tm_wday这类派生字段会干扰判断),得自定义时间相等的逻辑;- 要逐层遍历嵌套容器:
multiset→map→set<tm>,检查是否存在目标时间。
完整代码实现
#include <set> #include <map> #include <ctime> // 假设你的TrainType枚举定义如下(可根据实际调整) enum class TrainType { Local, Express, HighSpeed }; class TrainManager { private: std::multiset<std::pair<TrainType, std::map<std::string, std::set<std::tm>>>> m_oTrainGraphic; // 辅助函数:判断两个tm是否代表同一时间(忽略派生字段) bool isSameTime(const std::tm& t1, const std::tm& t2) const { return t1.tm_year == t2.tm_year && t1.tm_mon == t2.tm_mon && t1.tm_mday == t2.tm_mday && t1.tm_hour == t2.tm_hour && t1.tm_min == t2.tm_min && t1.tm_sec == t2.tm_sec; // 忽略tm_wday, tm_yday, tm_isdst这些由日期计算得出的字段 } public: bool DeleteTrain(const std::tm& time) { bool deleted = false; auto it = m_oTrainGraphic.begin(); while (it != m_oTrainGraphic.end()) { // 检查当前multiset元素是否包含目标时间 const auto& trainMap = it->second; bool containsTargetTime = false; // 遍历map中的每个时间集合 for (const auto& mapEntry : trainMap) { const auto& timeSet = mapEntry.second; // 遍历时间集合找匹配项 for (const auto& tmEntry : timeSet) { if (isSameTime(tmEntry, time)) { containsTargetTime = true; break; } } if (containsTargetTime) break; } if (containsTargetTime) { // 删除当前元素,erase返回下一个有效迭代器 it = m_oTrainGraphic.erase(it); deleted = true; } else { // 无匹配,迭代器正常前进 ++it; } } return deleted; } // 其他成员方法(比如插入元素的方法)... };
关键细节解释
- 移除
const修饰:因为DeleteTrain需要修改成员容器,所以不能是const成员函数; - 自定义时间比较:标准库没有给
tm提供合适的相等判断,逐成员比较会包含tm_wday这类不需要的字段,所以自己实现逻辑更可靠; - 安全遍历删除:用
while循环替代范围for,因为erase会让当前迭代器失效,必须用它返回的迭代器继续遍历; - 嵌套容器检查:从
multiset的每个元素开始,逐层深入map和set,只要找到匹配时间就删除整个multiset元素。
如果你实际需求是只删除set<tm>中的匹配时间,而非整个multiset元素,可以用下面的变体实现:
// 变体:仅删除时间集合中的匹配项,保留multiset元素 bool DeleteTrainTime(const std::tm& time) { bool deleted = false; for (auto& trainEntry : m_oTrainGraphic) { auto& trainMap = trainEntry.second; for (auto& mapEntry : trainMap) { auto& timeSet = mapEntry.second; auto it = timeSet.begin(); while (it != timeSet.end()) { if (isSameTime(*it, time)) { it = timeSet.erase(it); deleted = true; } else { ++it; } } } } return deleted; }
内容的提问来源于stack exchange,提问作者K.Krunk
相关产品推荐
相关产品推荐

