受限无向图场景下智能指针的正确使用方案咨询
C++智能指针重构方案:节点连接模型
核心思路
明确所有权关系是解决内存泄漏的关键:
- 顶层容器持有所有节点的所有权,用
std::shared_ptr管理 - 节点内部的交叉引用(包括自引用)用
std::weak_ptr,避免循环引用导致的内存泄漏 - 禁止裸指针直接持有对象,所有指针访问需通过智能指针的安全检查
重构后的代码实现
#include <memory> #include <vector> // 基类继承enable_shared_from_this,允许节点获取自身的智能指针 struct Node : std::enable_shared_from_this<Node> {}; struct Conn { // 用weak_ptr存储owner,避免自引用导致的循环引用 std::weak_ptr<Node> owner; // targets存储sink节点的弱引用,不持有所有权 std::vector<std::weak_ptr<Node>> targets; // 其他字段 }; struct NodeA : public Node { Conn conn; NodeA() { // 初始化owner为自身的弱引用 conn.owner = shared_from_this(); } // 安全添加目标节点的方法 void add_target(std::weak_ptr<Node> target) { conn.targets.push_back(std::move(target)); } // 其他字段 }; struct NodeB : public Node { // 存储源节点的弱引用,替代原有的Conn&,避免悬空引用 std::weak_ptr<NodeA> source_node; // 构造函数传入源节点的智能指针 NodeB(std::weak_ptr<NodeA> src) : source_node(std::move(src)) {} // 安全获取Conn的方法,检查源节点是否存活 Conn* get_conn() { if (auto src = source_node.lock()) { return &src->conn; } return nullptr; // 源节点已销毁,返回空指针 } // 其他字段 }; // 顶层容器:持有所有节点的所有权 std::vector<std::shared_ptr<Node>> sink_nodes; // 存储sink节点(NodeB) std::vector<std::shared_ptr<NodeA>> source_nodes; // 存储源节点(NodeA)
使用示例
// 创建源节点,由source_nodes持有所有权 auto source = std::make_shared<NodeA>(); source_nodes.push_back(source); // 创建sink节点,关联到源节点,由sink_nodes持有所有权 auto sink = std::make_shared<NodeB>(source); sink_nodes.push_back(sink); // 将sink节点添加到源节点的target列表 source->add_target(sink); // 访问NodeB的Conn时,先检查源节点是否存活 if (auto conn = sink->get_conn()) { // 安全操作conn }
关键细节说明
- 所有权隔离:顶层容器是唯一持有节点所有权的地方,
shared_ptr确保节点在不再被需要时自动销毁 - 避免循环引用:所有内部引用(包括Conn的owner、targets,NodeB的源节点引用)都用
weak_ptr,不会增加引用计数,彻底解决循环引用导致的内存泄漏 - 安全访问:使用
weak_ptr::lock()获取shared_ptr来访问对象,自动检查对象是否存活,避免悬空指针问题 - 替代裸引用:原NodeB中的
Conn&替换为weak_ptr<NodeA>,避免源节点销毁后引用失效的风险
内容的提问来源于stack exchange,提问作者Simon04090
相关产品推荐
相关产品推荐

