之前我已经制作了一些链接列表,这些概念对我来说都很有意义,但是对于一个项目我必须在C ++中制作一个模板,我没有用过很多,我遇到了一些麻烦。请帮忙。我花了太多时间在这么简单的事情上。
我已经有了一些列表类,但问题出在这里。当我在测试用例中创建三个节点并将它们全部链接起来时,如果我调用
node1.getNext().show();
工作正常,但如果我
node1.getNext().getNext().show();
我得到了一个段错误(核心转储)。这有什么不对?我已经尝试多次更改getNext()和getPrev()返回值的指针而没有运气。我觉得这个问题很愚蠢,但我遇到了一些麻烦。我的节点类在下面,然后是一个提供段错误的示例测试用例。
Node.h:
template <class T> class Node
{
public:
Node();
Node(T value);
void setPrev(Node<T> node);
void setValue(T value);
void setNext(Node<T> node);
Node<T> getPrev();
T getValue();
Node<T> getNext();
void show();
~Node() { }
private:
Node<T> *prev;
Node<T> *next;
T value;
};
//default construct
template <class T> Node<T>::Node() {
this->prev = NULL;
this->value = NULL;
this->next = NULL;
};
//overloaded construct
template <class T> Node<T>::Node(T value) {
this->prev = NULL;
this->value = value;
this->next = NULL;
}
template <class T> void Node<T>::setPrev(Node<T> node) {
this->prev = &node;
}
template <class T> void Node<T>::setValue(T value) {
this->value = value;
}
template <class T> void Node<T>::setNext(Node<T> node) {
this->next = &node;
}
template <class T> Node<T> Node<T>::getPrev() {
return this->prev;
}
template <class T> T Node<T>::getValue() {
return this->value;
}
template <class T> Node<T> Node<T>::getNext() {
return this->next;
}
template <class T>
void Node<T>::show() {
cout << value << endl;
}
测试用例:
int main(int argc, char **argv) {
typedef Node<int> IntNode;
IntNode head(NULL);
IntNode node1(23);
IntNode node2(45);
IntNode node3(77);
IntNode tail(NULL);
node1.setPrev(head);
node1.setNext(node2);
node2.setPrev(node1);
node2.setNext(node3);
node3.setPrev(node2);
node3.setNext(tail);
node1.show();
node2.show();
node3.show();
cout << node1.getNext().getValue() << endl;
cout << node1.getNext().getNext().getValue() << endl;
}
答案 0 :(得分:4)
您需要通过引用而不是值传递值。
执行node1.setNext(node1)
后,setNext()
会在堆栈上获得node1
的副本,而不是您在main()
中定义的变量。退出setNext()
后,next
中存储的地址将不再有效。
首先,将函数setPrev和setNext重新定义为
template <class T> void Node<T>::setPrev(Node<T> &node) {
this->prev = &node;
}
template <class T> void Node<T>::setNext(Node<T> &node) {
this->next = &node;
}
这将解决你的直接段错误。但是,您确实需要更多地考虑代码的设计以及通过引用或值传递时会发生什么,正确地编写代码并避免进一步的问题。
答案 1 :(得分:2)
您应该将下一个/前一个成员存储为指针。设置上一个和下一个节点时,您将按值获取参数,从而进行复制。
这意味着当您单步执行.getNext()
中的第二个node1.getNext().getNext().getValue()
时,您会遇到一个悬空指针,这就是您的代码失败的原因。
手工添加节点很费力,像std::list
这样的工作方式是指向它拥有的集合的begin
和end
指针。当一个新节点被推到列表的前面或后面时,集合会创建节点,存储该值并链接准备好下一个节点和/或遍历的指针。
答案 2 :(得分:1)
最大的问题是,您的setNext
和setPrev
函数会按值获取其参数,因此您将获得在main中声明的节点的副本。
如果要继续此操作,请通过引用或指针传递这些参数。通过指针传递可能会产生更多的语义感,并防止出现这种意外错误。