LEMON框架中类内ArcMap成员初始化与赋值问题求助
解决LEMON库中ListDigraph与ArcMap作为类成员的初始化问题
问题根源
- LEMON的
ArcMap无默认构造函数,必须在构造时绑定到对应的Digraph对象 - 类定义中无法直接用同属类的
ListDigraph成员初始化ArcMap,因为此时类对象未完成构造,成员未初始化 ArcMap的赋值运算符为私有,无法先声明再绑定图对象
解决方案一:使用智能指针延迟初始化ArcMap
这种方式允许你在g完全构造后,再创建并绑定ArcMap:
- 修改类成员声明与
compute_graph函数:
class GraphSolver { public: void compute_graph() { // 初始化ArcMap,绑定到已构造的g length = std::make_unique<ListDigraph::ArcMap<int>>(g); for (auto const &t: seq_trips) { auto tid = t[0].trip_id; for (int i = 0; i < t.size() - 1; ++i) { auto from_sid = t[i].stop_id; auto to_sid = t[i + 1].stop_id; auto from_time = t[i].arrival_time; auto to_time = t[i + 1].arrival_time; auto delta = to_time - from_time; ListDigraph::Node from_node; ListDigraph::Node to_node; if (stop2node.find(from_sid) != stop2node.end()) from_node = stop2node.at(from_sid); else { from_node = g.addNode(); stop2node[from_sid] = from_node; } if (stop2node.find(to_sid) != stop2node.end()) to_node = stop2node.at(to_sid); else { to_node = g.addNode(); stop2node[to_sid] = to_node; } ListDigraph::Arc old_arc = findArc(g, from_node, to_node); if(old_arc == INVALID) { ListDigraph::Arc new_arc = g.addArc(from_node, to_node); (*length)[new_arc] = delta; } else { if((*length)[old_arc] < delta) (*length)[old_arc] = delta; } } } } // 其他成员声明 SeqTrips seq_trips; MapStop2Idx stop2idx; VecStops stops; VecTrips trips; VecRoutes routes; ListDigraph g; unordered_map<size_t, ListDigraph::Node> stop2node; // 将ArcMap改为智能指针 std::unique_ptr<ListDigraph::ArcMap<int>> length; };
解决方案二:构造函数初始化列表(推荐)
通过构造函数初始化列表,利用成员声明顺序确保g先于ArcMap初始化:
- 调整成员声明顺序(必须
g在前,length在后),并添加构造函数:
class GraphSolver { public: // 构造函数初始化列表,用已初始化的g创建length和node2stop GraphSolver() : length(g), node2stop(g) {} void compute_graph() { for (auto const &t: seq_trips) { auto tid = t[0].trip_id; for (int i = 0; i < t.size() - 1; ++i) { auto from_sid = t[i].stop_id; auto to_sid = t[i + 1].stop_id; auto from_time = t[i].arrival_time; auto to_time = t[i + 1].arrival_time; auto delta = to_time - from_time; ListDigraph::Node from_node; ListDigraph::Node to_node; if (stop2node.find(from_sid) != stop2node.end()) from_node = stop2node.at(from_sid); else { from_node = g.addNode(); stop2node[from_sid] = from_node; node2stop[from_node] = from_sid; } if (stop2node.find(to_sid) != stop2node.end()) to_node = stop2node.at(to_sid); else { to_node = g.addNode(); stop2node[to_sid] = to_node; node2stop[to_node] = to_sid; } ListDigraph::Arc old_arc = findArc(g, from_node, to_node); if(old_arc == INVALID) { ListDigraph::Arc new_arc = g.addArc(from_node, to_node); length[new_arc] = delta; } else { if(length[old_arc] < delta) length[old_arc] = delta; } } } } // 成员声明顺序:先g,再依赖g的成员 ListDigraph g; unordered_map<size_t, ListDigraph::Node> stop2node; ListDigraph::ArcMap<int> length; ListDigraph::NodeMap<int> node2stop; // 改为类成员,避免每次调用函数重新创建 // 其他成员 SeqTrips seq_trips; MapStop2Idx stop2idx; VecStops stops; VecTrips trips; VecRoutes routes; };
关键注意点:C++类成员的初始化顺序严格按照类中声明的顺序,而非构造函数初始化列表的顺序。因此必须将g放在length和node2stop之前声明,否则会在未构造的g上创建ArcMap,导致未定义行为。
额外提示
原代码中node2stop是compute_graph内的局部变量,每次调用函数都会重新初始化。如果需要保留节点与站点的映射关系,建议将其改为类成员,如同方案二中的修改。
内容的提问来源于stack exchange,提问作者Claudio Tomasi
相关产品推荐
相关产品推荐

