Mojo中如何加载内存仅存类型指针?图结构实现遇阻
Mojo实现图结构时Pointer.load()报错的解决方法
问题描述
手动实现图结构的Node和NodeEdge结构体,NodeEdge通过Pointer[Node]存储关联节点的指针,但在printFirstEdgeNode函数中调用pointer.load()加载Node对象时触发错误,需要找到可行的实现方式完成关联节点的打印需求。
原代码
from memory import Pointer from collections import List struct NodeEdge: var node1P: Pointer[Node] var node2P: Pointer[Node] var edgeWeight: UInt16 fn __init__(inout self, inout node1: Node, inout node2: Node, weight: UInt16) -> NoneType: self.node1P = Pointer[Node].address_of(node1) self.node2P = Pointer[Node].address_of(node2) self.edgeWeight = weight node1.addEdge(self) node2.addEdge(self) fn __copyinit__(inout self, node1: NodeEdge) -> NoneType: self.node1P = node1.node1P self.node2P = node1.node2P self.edgeWeight = node1.edgeWeight fn __moveinit__(inout self, owned node1: NodeEdge) -> NoneType: self.node1P = node1.node1P self.node2P = node1.node2P self.edgeWeight = node1.edgeWeight struct Node: var nodeType: String var nodeData: List[UInt16] var nodeEdges: List[NodeEdge] fn __init__(inout self) -> NoneType: self.nodeType = '' self.nodeData = List[UInt16]() self.nodeEdges = List[NodeEdge]() fn __init__(inout self, ntype: String, data: List[UInt16], edges: List[NodeEdge]) -> NoneType: self.nodeType = ntype self.nodeData = data self.nodeEdges = edges fn addEdge(inout self, edge: NodeEdge) -> NoneType: self.nodeEdges.append(edge) fn setNodeType(inout self, ntype: String) -> NoneType: self.nodeType = ntype fn setNodeData(inout self, data: List[UInt16]) -> NoneType: self.nodeData = data fn setNodeEdgeData(inout self, data: List[NodeEdge]) -> NoneType: self.nodeEdges = data fn printNode(inout self) -> String: var res: String res = self.nodeType + "\n" for i in range(self.nodeData.size): res.__iadd__(self.nodeData[i]) res.__iadd__(" ") res.__iadd__("\n") for i in range(self.nodeEdges.size): res.__iadd__(self.nodeEdges[i].edgeWeight) res.__iadd__(" ") res.__iadd__("\n") return res fn printFirstEdgeNode(inout self) -> String: var res: String var firstNodeEdge = self.nodeEdges[0] var pSelf = Pointer[Node].address_of(self) if (pSelf.__eq__(firstNodeEdge.node1P)): # 错误发生在这里 var nodeToPrint = firstNodeEdge.node2P.load() else: # 打印另一个节点 pass return '' fn main(): var node1 = Node() var ndata1: List[UInt16] var node2 = Node() var ndata2: List[UInt16] ndata1 = List[UInt16](17) ndata2 = List[UInt16](12,2) node1.setNodeType("Sum") node2.setNodeType("Path") node1.setNodeData(ndata1) node2.setNodeData(ndata2) createEdges(node1, node2) print(node1.printFirstEdgeNode()) fn createEdges(inout node1: Node, inout node2: Node) -> NoneType: var edge = NodeEdge(node1, node2, 5)
错误原因
- 内存生命周期问题:代码中的
Node是栈分配的局部变量,当NodeEdge被复制到Node的nodeEdges列表中时,原指针指向的栈对象可能因作用域结束而销毁,或者指针指向的内存地址不再有效。 - Mojo的安全限制:
Pointer.load()要求指针指向的对象必须是堆分配且拥有稳定的内存地址,栈分配的结构体不满足此要求,直接加载会触发内存安全错误。
可行解决方案
方案1:使用堆分配的Node(Box包裹)
将Node用Box包裹,确保内存地址稳定,修改后的核心代码如下:
from memory import Pointer from collections import List from pointers import Box struct NodeEdge: var node1P: Pointer[Box[Node]] var node2P: Pointer[Box[Node]] var edgeWeight: UInt16 fn __init__(inout self, inout node1: Box[Node], inout node2: Box[Node], weight: UInt16) -> NoneType: self.node1P = Pointer[Box[Node]].address_of(node1) self.node2P = Pointer[Box[Node]].address_of(node2) self.edgeWeight = weight node1[].addEdge(self) node2[].addEdge(self) # 复制、移动构造函数保持不变... struct Node: # 结构体内容保持不变,仅修改printFirstEdgeNode: fn printFirstEdgeNode(inout self) -> String: var res: String var firstNodeEdge = self.nodeEdges[0] var nodeBox = firstNodeEdge.node2P.load() var nodeToPrint = nodeBox[] res = nodeToPrint.nodeType + " " for num in nodeToPrint.nodeData: res.__iadd__(num) res.__iadd__(" ") return res fn main(): var node1 = Box[Node]() var ndata1: List[UInt16] var node2 = Box[Node]() var ndata2: List[UInt16] ndata1 = List[UInt16](17) ndata2 = List[UInt16](12,2) node1[].setNodeType("Sum") node2[].setNodeType("Path") node1[].setNodeData(ndata1) node2[].setNodeData(ndata2) createEdges(node1, node2) print(node1[].printFirstEdgeNode()) fn createEdges(inout node1: Box[Node], inout node2: Box[Node]) -> NoneType: var edge = NodeEdge(node1, node2, 5)
方案2:用ID索引代替指针
给每个Node分配唯一ID,用容器管理所有节点,NodeEdge存储节点ID,避免指针问题:
from collections import List, Dict struct NodeEdge: var node1Id: UInt64 var node2Id: UInt64 var edgeWeight: UInt16 fn __init__(inout self, node1Id: UInt64, node2Id: UInt64, weight: UInt16) -> NoneType: self.node1Id = node1Id self.node2Id = node2Id self.edgeWeight = weight struct Node: var nodeId: UInt64 var nodeType: String var nodeData: List[UInt16] var nodeEdges: List[NodeEdge] fn __init__(inout self, nodeId: UInt64) -> NoneType: self.nodeId = nodeId self.nodeType = '' self.nodeData = List[UInt16]() self.nodeEdges = List[NodeEdge]() # 其他方法保持不变,修改printFirstEdgeNode: fn printFirstEdgeNode(inout self, allNodes: Dict[UInt64, Node]) -> String: var res: String var firstEdge = self.nodeEdges[0] var targetId = if firstEdge.node1Id == self.nodeId: firstEdge.node2Id else firstEdge.node1Id var targetNode = allNodes[targetId] res = targetNode.nodeType + "\n" for num in targetNode.nodeData: res.__iadd__(num) res.__iadd__(" ") return res fn main(): var allNodes = Dict[UInt64, Node]() var node1 = Node(1) var ndata1 = List[UInt16](17) node1.setNodeType("Sum") node1.setNodeData(ndata1) allNodes[1] = node1 var node2 = Node(2) var ndata2 = List[UInt16](12,2) node2.setNodeType("Path") node2.setNodeData(ndata2) allNodes[2] = node2 var edge = NodeEdge(1, 2, 5) allNodes[1].addEdge(edge) allNodes[2].addEdge(edge) print(allNodes[1].printFirstEdgeNode(allNodes))
说明
方案1适合需要直接访问节点内存的场景,依赖堆分配保证内存稳定性;方案2更安全,通过ID索引避免指针生命周期问题,适合大多数图结构实现场景。
内容的提问来源于stack exchange,提问作者Ethan Harness
相关产品推荐
相关产品推荐

