这里是C++初学者。我读到过返回对函数的局部变量的引用是不好的做法,因为当函数返回时,它超出了作用域。我理解这是为什么,但我想知道是否可以返回对类成员的引用。
我正在编写一个简单的图实现,它是一个邻接表,有一个函数insertNode
,它将一个Node
对象添加到Graph
类的std::vector<Node>
类型的成员变量中,并返回一个对刚添加到向量中的节点的引用。insertNode
的实现是:
//graph.cpp
Node* Graph::insertNode(Node n) {
this->nodeArray.push_back(n);
return &(this->nodeArray.back());
}
其中Graph类为:
//graph.h
class Graph {
private:
vector<Node> nodeArray;
public:
// Constructor
Graph();
Node* insertNode(Node n);
vector<Node> getNodes();
void connectNodes(Node* a, Node* b, int edgeWeight);
};
节点类为:
//node.h
class Node {
private:
list<Edge> edgeList;
string nodeName;
pair <int, int> coordinates;
public:
Node();
Node(string nodeName, int x, int y);
void setNodeName(string nodeName);
void setXY(int x, int y);
void insertEdge(Edge edgeToAdd);
void removeEdge(Edge fromEdge, Edge toEdge);
list<Edge> getEdgeList();
};
我用这种方式实现了insertGraph
,因为我需要返回一个指向节点的指针,该节点是为了在connectNodes
中使用而添加的,connectNodes
是一个在两个节点之间创建Edge
对象并更新每个节点上的边列表的函数,其中边的源节点和目的节点只是指向节点本身的指针。
我遇到的问题是,在以下代码(作为测试用例的一部分)中,当我第一次调用insertNode
时,我可以在IDE的监视器中看到它返回指向所添加节点的指针,并且此地址的内容是正确的,但是在使用不同的Node对象连续调用insertNode
时,返回的第一个指针似乎被修改了。
//test.cpp
SECTION("connects two nodes with an edge") {
Graph g = Graph();
Node a = Node("Johannesburg", 5, 10);
Node b = Node("Cape Town", 26, 10);
Node* aptr = g.insertNode(a); //first call
Node* bptr = g.insertNode(b); //second call
g.connectNodes(aptr, bptr, 1);
在第一次调用insertNode
传递a
之后,aptr
看起来如下所示:
在第二次调用insertNode
传递b
之后,aptr
更改为:
为什么会出现这种行为?我犯了糟糕的C++代码中的哪一个原罪?如果这确实是问题所在,那么实现insertNode
函数的更好方法是什么?
2条答案
按热度按时间pkwftd7m1#
std::vector
不是基于节点的容器;因此,在push_back
或emplace_back
调用之后,如果新的size
超过旧的capacity
,则会发生向量的完全重新分配,从而导致先前引用该向量的所有指针和迭代器失效。由于您使用的是向量(具有连续内存分配),因此您可以受益于其随机访问属性并将索引(而不是指针)存储到元素:因为索引不会因为向量增长而失效;并且可以对照
size
检查它们以确保在可能的收缩操作(erase
、remove
、clear
...)的情况下的有效性。因为即使向量可以增长到最大索引值,到最后一个元素的索引仍然比其大小小1。pvcm50d12#
向量为一些对象分配空间。这被称为
capacity
。当你push_back()
一个项目时,向量的size
会改变,但capacity
不会改变。然而,在某个时候,capacity
将不再足以容纳push_back
ed项目,向量将需要分配新的内存。它会分配更多的内存,这样
capacity
会再次大于size
。有些实现每次会将内存量增加一倍,有些则增加50%。在有足够的存储空间后,向量会将对象从旧位置移动到新位置。因此,它们的地址改变了,旧的存储空间是free
d或delete
d,因此用你保留的指针访问那个位置是未定义的行为。您可以重新考虑您的算法,或者使用指向Nodes的指针向量,以便移动的不是实际的节点,而是它们的指针。