为什么我无法对std::set中Vertex对象的vector成员调用push_back?
核心问题解答
std::set的迭代器属于常量迭代器范畴,->运算符返回的是const T*类型的指针,指向的是常量对象,你无法通过该指针修改对象的成员。
原因是std::set是有序关联容器,容器的排序逻辑依赖元素本身的值,一旦允许随意修改元素内容,会直接破坏容器内部的有序结构,引发未定义行为,因此C++标准强制要求std::set迭代器返回只读的常量对象。
代码执行失败的两个直接原因
- 迭代器有效性判断顺序错误
你先对it1解引用构造p1,再判断it1 != vertices_.end(),如果传入的c1不在顶点集合中,it1就是end()迭代器,解引用空迭代器直接触发崩溃。 - 尝试修改set的常量元素
即使it1是有效迭代器,你通过it1->neighbors访问到的是const std::vector<...>,调用push_back修改常量对象的成员,属于编译期就不允许的操作,如果你的代码是运行期崩溃大概率是第一个问题,要是编译失败就是第二个问题。
另外你当前的边插入逻辑也存在问题:你构造的p1是当前顶点和权重的pair,相当于把自己加入自己的邻接表,正常应该是把*it2(对端顶点)加入it1的邻接表。
修复方案
方案1:用mutable修饰不参与排序的成员
因为你的Vertex类的排序、判等逻辑只用到ID_字段,neighbors的修改完全不影响容器的有序性,你可以给neighbors加mutable修饰,允许在常量对象上修改该成员:
mutable std::vector<std::pair<Vertex, int>> neighbors;
方案2:替换容器为std::map(更推荐)
你可以把顶点集合改成std::map<char, Vertex>,键是顶点ID,值是顶点对象,map的有序性只由键保证,值可以随意修改,不需要额外改Vertex类的定义:
// 修改Graph类的成员定义 protected: std::map<char, Vertex> vertices_; // 对应的insertEdge逻辑调整 void Graph::insertEdge(char c1, char c2, int w) { auto it1 = vertices_.find(c1); auto it2 = vertices_.find(c2); // 先判断两个顶点都存在 if(it1 != vertices_.end() && it2 != vertices_.end()) { it1->second.neighbors.emplace_back(it2->second, w); // 如果是无向图还要加反向边:it2->second.neighbors.emplace_back(it1->second, w); } }
内容的提问来源于stack exchange,提问作者Jib Ran
相关产品推荐
相关产品推荐

