You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向空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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 09:43:17