向空std::list添加指针的正确方式及段错误排查
问题背景与代码
我有两个用于表示连通图结构中节点和边的简单类:
Node类定义(node.h)
//node.h #include "edge.h" #include <string> #include <list> #include <utility> using namespace std; class Edge; class Node { private: list<Edge> edgeList; string nodeName; pair <int, int> coordinates; public: Node(); void setXY(int x, int y); void insertEdge(Edge& edgeToAdd); void removeEdge(Edge& edgeToAdd); list<Edge> getEdgeList(); };
insertEdge方法实现(node.cpp)
void Node::insertEdge(Edge& edgeToAdd) { this->edgeList.push_back(edgeToAdd); }
Edge类定义(edge.h)
#pragma once #include "node.h" class Node; class Edge { private: Node* destinationNode; int edgeWeight; public: //constructor Edge(Node* destNode, int w); //Setters and Getters void setDestinationNode(Node* destNode); void setEdgeWeight(int weight); Node* getDestinationNode(); int getEdgeWeight(); };
测试代码中的问题
在单元测试中我尝试调用insertEdge插入Edge对象,代码如下:
SECTION("an edge gets inserted to the adjacency list") { Node* b = &Node(); Edge* e = new Edge(b,1); b->insertEdge(*e); list<Edge> edgelist = b->getEdgeList(); }
运行时出现段错误,调试发现是edgeList.push_back(edgeToAdd)触发了非法内存访问,涉及std::list分配器的_Prev和_Next成员。我怀疑和std::list<Edge*> edgeList的声明方式有关,想问:向仅完成声明的std::list添加指针的正确方式是什么?
问题分析与解决方案
首先,你的段错误根本原因不是list的声明方式,而是测试代码里的致命错误:
Node* b = &Node();这行取了临时Node对象的地址。临时对象在该行执行完毕后就会被销毁,后续通过b指针访问已销毁的Node,属于访问悬空指针,必然触发未定义行为(比如段错误)。
1. 修复测试代码的悬空指针问题
把临时对象改成栈对象或堆分配对象:
- 方式一:用栈对象(推荐,避免内存泄漏)
SECTION("an edge gets inserted to the adjacency list") { Node b; // 栈上创建Node,生命周期覆盖整个测试段 Edge* e = new Edge(&b,1); b.insertEdge(*e); list<Edge> edgelist = b.getEdgeList(); delete e; // 释放堆分配的Edge }
- 方式二:用堆分配Node
SECTION("an edge gets inserted to the adjacency list") { Node* b = new Node(); Edge* e = new Edge(b,1); b->insertEdge(*e); list<Edge> edgelist = b->getEdgeList(); delete e; delete b; // 释放Node }
2. 关于list存储指针的问题(如果确实需要)
如果你想让list存储Edge指针而非Edge对象,需要修改Node类的定义:
- 在node.h中把
list<Edge> edgeList;改成list<Edge*> edgeList; - 对应修改insertEdge方法:
void Node::insertEdge(Edge* edgeToAdd) { this->edgeList.push_back(edgeToAdd); }
- 测试代码调用时直接传指针:
b->insertEdge(e);
注意:存储裸指针需要手动管理内存,容易引发泄漏;改用std::shared_ptr<Edge>这类智能指针会更安全,无需手动释放。
3. 额外修复头文件循环依赖问题
你的node.h和edge.h互相包含,会导致编译错误。解决办法:
- node.h中去掉
#include "edge.h",保留class Edge;前向声明即可(Node类仅用到Edge类型,无需完整定义) - edge.h中保留
class Node;前向声明即可(Edge仅用到Node指针,无需完整定义)
内容的提问来源于stack exchange,提问作者Blargian
相关产品推荐
相关产品推荐

